(lhs: Self, rhs: Other) -> Bool
+
/// Returns a Boolean value indicating whether the first pointer references
/// a memory location earlier than the second pointer references.
///
diff --git a/proposals/0335-existential-any.md b/proposals/0335-existential-any.md
new file mode 100644
index 0000000000..eaf480380e
--- /dev/null
+++ b/proposals/0335-existential-any.md
@@ -0,0 +1,303 @@
+# Introduce existential `any`
+
+* Proposal: [SE-0335](0335-existential-any.md)
+* Authors: [Holly Borla](https://github.com/hborla)
+* Review Manager: [Doug Gregor](https://github.com/DougGregor)
+* Status: **Implemented (Swift 5.6)**
+* Upcoming Feature Flag: `ExistentialAny` (implemented in Swift 5.8)
+* Implementation: [apple/swift#40282](https://github.com/apple/swift/pull/40282)
+* Decision Notes: [Acceptance](https://forums.swift.org/t/accepted-with-modifications-se-0335-introduce-existential-any/54504)
+
+## Contents
+ - [Introduction](#introduction)
+ - [Motivation](#motivation)
+ - [Proposed solution](#proposed-solution)
+ - [Detailed design](#detailed-design)
+ - [Grammar of explicit existential types](#grammar-of-explicit-existential-types)
+ - [Semantics of explicit existential types](#semantics-of-explicit-existential-types)
+ - [`Any` and `AnyObject`](#any-and-anyobject)
+ - [Metatypes](#metatypes)
+ - [Type aliases and associated types](#type-aliases-and-associated-types)
+ - [Source compatibility](#source-compatibility)
+ - [Effect on ABI stability](#effect-on-abi-stability)
+ - [Effect on API resilience](#effect-on-api-resilience)
+ - [Alternatives considered](#alternatives-considered)
+ - [Rename `Any` and `AnyObject`](#rename-any-and-anyobject)
+ - [Use `Any` instead of `any P`](#use-anyp-instead-of-any-p)
+ - [Future Directions](#future-directions)
+ - [Extending existential types](#extending-existential-types)
+ - [Re-purposing the plain protocol name](#re-purposing-the-plain-protocol-name)
+ - [Revisions](#revisions)
+ - [Changes from the pitch discussion](#changes-from-the-pitch-discussion)
+ - [Acknowledgments](#acknowledgments)
+
+## Introduction
+
+Existential types in Swift have an extremely lightweight spelling: a plain protocol name in type context means an existential type. Over the years, this has risen to the level of **active harm** by causing confusion, leading programmers down the wrong path that often requires them to re-write code once they hit a fundamental [limitation of value-level abstraction](https://forums.swift.org/t/improving-the-ui-of-generics/22814#heading--limits-of-existentials). This proposal makes the impact of existential types explicit in the language by annotating such types with `any`.
+
+Swift evolution discussion thread: [[Pitch] Introduce existential `any`](https://forums.swift.org/t/pitch-introduce-existential-any/53520).
+
+## Motivation
+
+Existential types in Swift have significant limitations and performance implications. Some of their limitations are missing language features, but many are fundamental to their type-erasing semantics. For example, given a protocol with associated type requirements, the existential type cannot conform to the protocol itself without a manual conformance implementation, because there is not an obvious concrete associated type that works for any value conforming to the protocol, as shown by the following example:
+
+```swift
+protocol P {
+ associatedtype A
+ func test(a: A)
+}
+
+func generic(p: ConcreteP, value: ConcreteP.A) {
+ p.test(a: value)
+}
+
+func useExistential(p: P) {
+ generic(p: p, value: ???) // what type of value would P.A be??
+}
+```
+
+Existential types are also significantly more expensive than using concrete types. Because they can store any value whose type conforms to the protocol, and the type of value stored can change dynamically, existential types require dynamic memory unless the value is small enough to fit within an inline 3-word buffer. In addition to heap allocation and reference counting, code using existential types incurs pointer indirection and dynamic method dispatch that cannot be optimized away.
+
+Despite these significant and often undesirable implications, existential types have a minimal spelling. Syntactically, the cost of using one is hidden, and the similar spelling to generic constraints has caused many programmers to confuse existential types with generics. In reality, the need for the dynamism they provided is relatively rare compared to the need for generics, but the language makes existential types too easy to reach for, especially by mistake. The cost of using existential types should not be hidden, and programmers should explicitly opt into these semantics.
+
+## Proposed solution
+
+I propose to make existential types syntactically explicit in the language using the `any` keyword. This proposal introduces the new syntax in the Swift 5 language mode, and this syntax should be required for existential types under a future language mode.
+
+In Swift 5, anywhere that an existential type can be used today, the `any` keyword can be used to explicitly denote an existential type:
+
+```swift
+// Swift 5 mode
+
+protocol P {}
+protocol Q {}
+struct S: P, Q {}
+
+let p1: P = S() // 'P' in this context is an existential type
+let p2: any P = S() // 'any P' is an explicit existential type
+
+let pq1: P & Q = S() // 'P & Q' in this context is an existential type
+let pq2: any P & Q = S() // 'any P & Q' is an explicit existential type
+```
+
+In a future language mode, existential types are required to be explicitly spelled with `any`:
+
+```swift
+// Future language mode
+
+protocol P {}
+protocol Q {}
+struct S: P, Q {}
+
+let p1: P = S() // error
+let p2: any P = S() // okay
+
+let pq1: P & Q = S() // error
+let pq2: any P & Q = S() // okay
+```
+
+This behavior can be enabled in earlier language modes with the [upcoming feature flag](0362-piecemeal-future-features.md) `ExistentialAny`.
+
+## Detailed design
+
+### Grammar of explicit existential types
+
+This proposal adds the following production rules to the grammar of types:
+
+```
+type -> existential-type
+
+existential-type -> 'any' type
+```
+
+### Semantics of explicit existential types
+
+The semantics of `any` types are the same as existential types today. Explicit `any` can only be applied to protocols and protocol compositions, or metatypes thereof; `any` cannot be applied to nominal types, structural types, type parameters, and protocol metatypes:
+
+```swift
+struct S {}
+
+let s: any S = S() // error: 'any' has no effect on concrete type 'S'
+
+func generic(t: T) {
+ let x: any T = t // error: 'any' has no effect on type parameter 'T'
+}
+
+let f: any ((Int) -> Void) = generic // error: 'any' has no effect on concrete type '(Int) -> Void'
+```
+
+#### `Any` and `AnyObject`
+
+`any` is unnecessary for `Any` and `AnyObject` (unless part of a protocol composition):
+
+```swift
+struct S {}
+class C {}
+
+let value: any Any = S()
+let values: [any Any] = []
+let object: any AnyObject = C()
+
+protocol P {}
+extension C: P {}
+
+let pObject: any AnyObject & P = C() // okay
+```
+
+> **Rationale**: `any Any` and `any AnyObject` are redundant. `Any` and `AnyObject` are already special types in the language, and their existence isn’t nearly as harmful as existential types for regular protocols because the type-erasing semantics is already explicit in the name.
+
+#### Metatypes
+
+The existential metatype, i.e. `P.Type`, becomes `any P.Type`. The protocol metatype, i.e. `P.Protocol`, becomes `(any P).Type`. The protocol metatype value `P.self` becomes `(any P).self`:
+
+```swift
+protocol P {}
+struct S: P {}
+
+let existentialMetatype: any P.Type = S.self
+
+protocol Q {}
+extension S: Q {}
+
+let compositionMetatype: any (P & Q).Type = S.self
+
+let protocolMetatype: (any P).Type = (any P).self
+```
+
+> **Rationale**: The existential metatype is spelled `any P.Type` because it's an existential type that is a generalization over metatypes. The protocol metatype is the singleton metatype of the existential type `any P` itself, which is naturally spelled `(any P).Type`.
+
+Under this model, the `any` keyword conceptually acts like an existential quantifier `∃ T`. Formally, `any P.Type` means `∃ T:P . T.Type`, i.e. for some concrete type `T` conforming to `P`, this is the metatype of that concrete type.`(any P).Type` is formally `(∃ T:P . T).Type`, i.e. the metatype of the existential type itself.
+
+The distinction between `any P.Type` and `(any P).Type` is syntactically very subtle. However, `(any P).Type` is rarely useful in practice, and it's helpful to explain why, given a generic context where a type parameter `T` is substituted with an existential type, `T.Type` is the singleton protocol metatype.
+
+##### Metatypes for `Any` and `AnyObject`
+
+Like their base types, `Any.Type` and `AnyObject.Type` remain valid existential metatypes; writing `any` on these metatypes in unnecessary. The protocol metatypes for `Any` and `AnyObject` are spelled `(any Any).Type` and `(any AnyObject).Type`, respectively.
+
+#### Type aliases and associated types
+
+Like plain protocol names, a type alias to a protocol `P` can be used as both a generic constraint and an existential type. Because `any` is explicitly an existential type, a type alias to `any P` can only be used as an existential type, it cannot be used as a generic conformance constraint, and `any` does not need to be written at the use-site:
+
+```swift
+protocol P {}
+typealias AnotherP = P
+typealias AnyP = any P
+
+struct S: P {}
+
+let p2: any AnotherP = S()
+let p1: AnyP = S()
+
+func generic(value: T) { ... }
+func generic(value: T) { ... } // error
+```
+
+Once the `any` spelling is required under a future language mode, a type alias to a plain protocol name is not a valid type witness for an associated type requirement; existential type witnesses must be explicit in the `typealias` with `any`:
+
+```swift
+protocol P {}
+
+protocol Requirements {
+ associatedtype A
+}
+
+struct S1: Requirements {
+ typealias A = P // error: associated type requirement cannot be satisfied with a protocol
+}
+
+struct S2: Requirements {
+ typealias A = any P // okay
+}
+```
+
+## Source compatibility
+
+Enforcing that existential types use the `any` keyword will require a source change. To ease the migration, I propose to start allowing existential types to be spelled with `any` with the Swift 5.6 compiler, and require existential types to be spelled with `any` under a future language mode. The old existential type syntax will continue to be supported under the Swift 5 language mode, and the transition to the new syntax is mechanical, so it can be performed automatically by a migrator.
+
+[SE-0309 Unlock existentials for all protocols](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0309-unlock-existential-types-for-all-protocols.md) enables more code to be written using existential types. To minimize the amount of new code written that will become invalid under `ExistentialAny`, I propose requiring `any` immediately for protocols with `Self` and associated type requirements. This introduces an inconsistency for protocols under the Swift 5 language mode, but this inconsistency already exists today (because you cannot use certain protocols as existential types at all), and the syntax difference serves two purposes:
+
+1. It saves programmers time in the long run by preventing them from writing new code that will become invalid later.
+2. It communicates the existence of `any` and encourages programmers to start using it for other existential types before adopting `ExistentialAny`.
+
+### Transitioning to `any`
+
+The new `any` syntax will be staged in over several major Swift releases. In the release where `any` is introduced, the compiler will not emit diagnostics for the lack of `any` on existential types, save for the aforementioned cases. After `any` is introduced, warnings will be added to guide programmers toward the new syntax. Finally, a missing `any` will become an unconditional error, or [plain protocol names may be repurposed](#re-purposing-the-plain-protocol-name) — in Swift 6 or a later language mode.
+
+## Effect on ABI stability
+
+None.
+
+## Effect on API resilience
+
+None.
+
+## Alternatives considered
+
+### Rename `Any` and `AnyObject`
+
+Instead of leaving `Any` and `AnyObject` in their existing spelling, an alternative is to spell these types as `any Value` and `any Object`, respectively. Though this is more consistent with the rest of the proposal, this change would have an even bigger source compatibility impact. Given that `Any` and `AnyObject` aren’t as harmful as other existential types, changing the spelling isn’t worth the churn.
+
+### Use `Any` instead of `any P`
+
+A common suggestion is to spell existential types with angle brackets on `Any`, e.g. `Any`. However, an important aspect of the proposed design is that `any` has symmetry with `some`, where both keywords can be applied to protocol constraints. This symmetry is important for helping programmers understand and remember the syntax, and for future extensions of the `some` and `any` syntax. Opaque types and existential types would both greatly benefit from being able to specify constraints on associated types. This could naturally be done in angle brackets, e.g. `some Sequence` and `any Sequence`, or `some Sequence<.Element == Int>` and `any Sequence<.Element == Int>`.
+
+Using the same syntax between opaque types and exsitential types also makes it very easy to replace `any` with `some`, and it is indeed the case that many uses of existential types today could be replaced with opaque types instead.
+
+Finally, the `Any` syntax is misleading because it appears that `Any` is a generic type, which is confusing to the mental model for 2 reasons:
+
+1. A generic type is something programmers can implement themselves. In reality, existential types are a built-in language feature that would be _very_ difficult to replicate with regular Swift code.
+2. This syntax creates the misconception that the underlying concrete type is a generic argument to `Any` that is preserved statically in the existential type. The `P` in `Any
` looks like an implicit type parameter with a conformance requirement, but it's not; the underlying type conforming to `P` is erased at compile-time.
+
+## Future Directions
+
+### Extending existential types
+
+This proposal provides an obvious syntax for extending existential types in order to manually implement protocol conformances:
+
+```swift
+extension any Equatable: Equatable { ... }
+```
+
+### Re-purposing the plain protocol name
+
+In other places in the language, a plain protocol name is already sugar for a type parameter conforming to the protocol. Consider a normal protocol extension:
+
+```swift
+extension Collection { ... }
+```
+
+This extension is a form of universal quantification; it extends all types that conform to `Collection`. This extension introduces a generic context with a type parameter ``, which means the above syntax is effectively sugar for a parameterized extension:
+
+```swift
+extension Self where Self: Collection { ... }
+```
+
+Changing the syntax of existential types creates an opportunity to expand upon this sugar. If existential types are spelled explicitly with `any`, a plain protocol name could always mean sugar for a type parameter on the enclosing context with a conformance requirement to the protocol. For example, consider the declaration of `append(contentsOf:)` from the standard library:
+
+```swift
+extension Array {
+ mutating func append(contentsOf newElements: S) where S.Element == Element
+}
+```
+
+Combined with a syntax for constraining associated types in angle brackets, such as in [[Pitch] Light-weight same-type constraint syntax](https://forums.swift.org/t/pitch-light-weight-same-type-constraint-syntax/52889), the above declaration could be simplified to:
+
+```swift
+extension Array {
+ mutating func append(contentsOf newElements: Sequence)
+}
+```
+
+This sugar eliminates a lot of noise in cases where a type parameter is only referred to once in a generic signature, and it enforces a natural model of abstraction, where programmers only need to name an entity when they need to refer to it multiple times.
+
+## Revisions
+
+### Changes from the pitch discussion
+
+* Spell the existential metatype as `any P.Type`, and the protocol metatype as `(any P).Type`.
+* Preserve `any` through type aliases.
+* Allow `any` on `Any` and `AnyObject`.
+
+## Acknowledgments
+
+Thank you to Joe Groff, who originally suggested this direction and syntax in [Improving the UI of generics](https://forums.swift.org/t/improving-the-ui-of-generics/22814), and to those who advocated for this change in the recent discussion about [easing the learning curve for generics](https://forums.swift.org/t/discussion-easing-the-learning-curve-for-introducing-generic-parameters/52891). Thank you to John McCall and Slava Pestov, who helped me figure out the implementation model.
diff --git a/proposals/0336-distributed-actor-isolation.md b/proposals/0336-distributed-actor-isolation.md
new file mode 100644
index 0000000000..bc7b91c704
--- /dev/null
+++ b/proposals/0336-distributed-actor-isolation.md
@@ -0,0 +1,1822 @@
+# Distributed Actor Isolation
+
+* Proposal: [SE-0336](0336-distributed-actor-isolation.md)
+* Authors: [Konrad 'ktoso' Malawski](https://github.com/ktoso), [Pavel Yaskevich](https://github.com/xedin), [Doug Gregor](https://github.com/DougGregor), [Kavon Farvardin](https://github.com/kavon)
+* Review Manager: [Joe Groff](https://github.com/jckarter)
+* Status: **Implemented (Swift 5.7)**
+* Decision Notes: [Acceptance](https://forums.swift.org/t/accepted-se-0336-distributed-actor-isolation/54726)
+* Implementation:
+ * Partially available in [recent `main` toolchain snapshots](https://swift.org/download/#snapshots) behind the `-enable-experimental-distributed` feature flag.
+ * This flag also implicitly enables `-enable-experimental-concurrency`.
+* Sample app:
+ * A sample app, showcasing how the various "pieces" work together is available here:
+ [https://github.com/apple/swift-sample-distributed-actors-transport](https://github.com/apple/swift-sample-distributed-actors-transport)
+
+## Table of Contents
+
+- [Distributed Actor Isolation](#distributed-actor-isolation)
+ - [Table of Contents](#table-of-contents)
+ - [Introduction](#introduction)
+ - [Useful links](#useful-links)
+ - [Motivation](#motivation)
+ - [Location Transparency](#location-transparency)
+ - [Remote and Local Distributed Actors](#remote-and-local-distributed-actors)
+ - [Proposed solution](#proposed-solution)
+ - [Distributed Actors](#distributed-actors)
+ - [Complete isolation of state](#complete-isolation-of-state)
+ - [Distributed Methods](#distributed-methods)
+ - [Detailed design](#detailed-design)
+ - [Distributed Actors and Distributed Actor Systems](#distributed-actors-and-distributed-actor-systems)
+ - [Distributed Actor Initializers](#distributed-actor-initializers)
+ - [Distributed Actors implicitly conform to Codable](#distributed-actors-implicitly-conform-to-codable)
+ - [Distributed Methods](#distributed-methods-1)
+ - [Distributed Method Serialization Requirements](#distributed-method-serialization-requirements)
+ - [Distributed Methods and Generics](#distributed-methods-and-generics)
+ - [Distributed Methods and Existential Types](#distributed-methods-and-existential-types)
+ - [Implicit effects on Distributed Methods](#implicit-effects-on-distributed-methods)
+ - [Isolation states and Implicit effects on Distributed Methods](#isolation-states-and-implicit-effects-on-distributed-methods)
+ - [Distributed Actor Properties](#distributed-actor-properties)
+ - [Stored properties](#stored-properties)
+ - [Computed properties](#computed-properties)
+ - [Protocol Conformances](#protocol-conformances)
+ - [The `DistributedActor` protocol and protocols inheriting from it](#the-distributedactor-protocol-and-protocols-inheriting-from-it)
+ - [Breaking through Location Transparency](#breaking-through-location-transparency)
+ - [Future Directions](#future-directions)
+ - [Versioning and Evolution of Distributed Actors and Methods](#versioning-and-evolution-of-distributed-actors-and-methods)
+ - [Evolution of parameter values only](#evolution-of-parameter-values-only)
+ - [Evolution of distributed methods](#evolution-of-distributed-methods)
+ - [Introducing the `local` keyword](#introducing-the-local-keyword)
+ - [Alternatives Considered](#alternatives-considered)
+ - [Implicitly `distributed` methods / "opt-out of distribution"](#implicitly-distributed-methods--opt-out-of-distribution)
+ - [Introducing "wrapper" type for `Distributed`](#introducing-wrapper-type-for-distributedsomeactor)
+ - [Creating only a library and/or source-generation tool](#creating-only-a-library-andor-source-generation-tool)
+ - [Acknowledgments & Prior Art](#acknowledgments--prior-art)
+ - [Source compatibility](#source-compatibility)
+ - [Effect on ABI stability](#effect-on-abi-stability)
+ - [Effect on API resilience](#effect-on-api-resilience)
+ - [Changelog](#changelog)
+
+## Introduction
+
+With the recent introduction of [actors](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0306-actors.md) to the language, Swift gained powerful and foundational building blocks for expressing *thread-safe* concurrent programs. This proposal is the first in a series of proposals aiming to extend Swift's actor runtime with the concept of *distributed actors*, allowing developers leverage the actor model not only in local, but also distributed settings.
+
+With distributed actors, we acknowledge that the world we live in is increasingly built around distributed systems, and that we should provide developers with better tools to work within those environments. We aim to simplify and push the state-of-the-art for distributed systems programming in Swift as we did with concurrent programming with local actors and Swift’s structured concurrency approach embedded in the language.
+
+> The distributed actor proposals will be structured similarly to how Swift Concurrency proposals were: as a series of interconnected proposals that build on top of each other.
+
+This proposal focuses on the extended actor isolation and type-checking aspects of distributed actors.
+
+#### Useful links
+
+Swift Evolution:
+
+- [Distributed Actors: Pitch #1](https://forums.swift.org/t/pitch-distributed-actors/51669) - a comprehensive, yet quite large, pitch encompassing all pieces of the distributed actor feature; It will be split out into smaller proposals going into the details of each subject, such that we can focus on, and properly review, its independent pieces step by step.
+
+While this pitch focuses _only_ on the actor isolation rules, we have work-in-progress transport implementations for distributed actors available as well. While they are work-in-progress and do not make use of the complete model described here, they may be useful to serve as reference for how distributed actors might be used.
+
+- [Swift Distributed Actors Library](https://www.swift.org/blog/distributed-actors/) - a reference implementation of a *peer-to-peer cluster* for distributed actors. Its internals depend on the work in progress language features and are dynamically changing along with these proposals. It is a realistic implementation that we can use as reference for these design discussions.
+- "[Fishy Transport](https://github.com/apple/swift-sample-distributed-actors-transport)" Sample - a simplistic example transport implementation that is easier to follow the basic integration pieces than the realistic cluster implementation. Feel free to refer to it as well, while keeping in mind that it is very simplified in its implementation approach.
+
+## Motivation
+
+Distributed actors are necessary to expand Swift's actor model to distributed environments. The new `distributed` keyword offers a way for progressively disclosing the additional complexities that come with multiprocess or multi-node environments, into the local-only actor model developers are already familiar with.
+
+Distributed actors need stronger isolation guarantees than those that are offered by Swift's "local-only" actors. This was a conscious decision, as part of making sure actors are convenient to use in the common scenario where they are only used as concurrency isolation domains. This convenience though is too permissive for distributed programming.
+
+This proposal introduces the additional isolation checks necessary to allow a distributed runtime to utilize actors as its primary building block, while keeping the convenience and natural feel of such actor types.
+
+### Location Transparency
+
+The design of distributed actors intentionally does not provide facilities to easily determine whether an instance is local or remote. The programmer should not _need_ to think about where the instance is located, because Swift will make it work in either case. There are numerous benefits to embracing location transparency:
+
+- The programmer can write a complex distributed systems algorithm and test it locally. Running that program on a cluster becomes merely a configuration and deployment change, without any additional source code changes.
+- Distributed actors can be used with multiple transports without changing the actor's implementation.
+- Actor instances can be balanced between nodes once capacity of a cluster changes, or be passivated when not in use, etc. There are many more advanced patterns for allocating instances, such as the "virtual actor" style as popularized by Orleans or Akka's cluster sharding.
+
+Swift's take on location transparency is expressed and enforced in terms of actor isolation. The same way as actors isolate their state to protect from local race conditions, distributed actors must isolate their state because the state "might not actually be available locally" while we're dealing with a remote distributed actor reference.
+
+It is also possible to pass distributed actors to distributed methods, if the actor is able to conform to the serialization requirements imposed on it by the actor system.
+
+### Remote and Local Distributed Actors
+
+For the purpose of this proposal, we omit the implementation details of a remote actor reference, however as the purpose of actor isolation is to erase the observable difference between a local and remote instance (to achieve location transparency), we need to at least introduce the general concept.
+
+It is, by design, not possible to *statically* determine if a distributed actor instance is remote or local, therefore all programming against a distributed actor must be done as-if it was remote. This is the root reason for most of the isolation rules introduced in this proposal. For example, the following snippet illustrates location transparency in action, where in our tests we use a local instance, but in a real deployment they would be remote instances communicating:
+
+```swift
+distributed actor TokenRange {
+ let range: (Token, Token)
+ var storage: [Token: Data]
+
+ init(...) { ... }
+
+ distributed func read(at loc: Token) -> Data? {
+ return storage[loc]
+ }
+
+ distributed func write(to loc: Token, data: Data) -> Data? {
+ let prev = storage[loc]
+ storage[loc] = data
+ return prev
+ }
+}
+```
+
+Which can be used in a local test:
+
+```swift
+func test_distributedTokenRange() async throws {}
+ let range = TokenRange(...)
+ try await assert(range.read(at: testToken) == nil)
+
+ try await write(to: testToken, someData)
+ try await assert(range.read(at: testToken) == someData)
+}
+```
+
+Distributed functions must be marked with `try` and `await` because they imply asynchronous network calls which may fail. While the `await` rule is the same as with local-only actors, the rule about distributed methods throwing is unique to them because of the assumption that underlying transport mechanisms can fail (i.e. network or serialization errors), regardless if the called function is able to throw or not.
+
+Note that the even though this test is strictly local -- there are no remote actors involved here at all -- the call-sites of distributed methods have implicitly gained the async and throwing effects, which means that we must invoke them with `try await dist.` This is an important aspect of the design, as it allows us to surface any potential network issues that might occur during these calls, such as timeouts, network failures or other issues that may have caused these calls to fail. This failure is a natural consequence of the calls potentially having to cross process or network boundaries. The asynchronous effect is similar, because we might be waiting for a long time for a response to arrive, distributed calls must be potential suspension points.
+
+We could write the same unit-test using a distributed remote actor, and the test would remain exactly the same:
+
+```swift
+func test_distributedTokenRange() async throws {}
+ // the range is actually 'remote' now
+ let range: TokenRange =
+ try await assert(range.read(at: testToken) == nil)
+
+ try await write(to: testToken, someData)
+ try await assert(range.read(at: testToken) == someData)
+}
+```
+
+During this proposal, we will be using the following phrases which have well-defined meanings, so in order to avoid confusion, let us define them explicitly up-front:
+
+- _distributed actor type_ - any `distributed actor` declaration, or `protocol` declaration that also conforms to `DistributedActor` because they can only be implemented by specific distributed actors, e.g. `protocol Worker: DistributedActor` as well as `distributed actor Worker`, both, can be referred to as "distributed actor type"
+- _distributed actor reference_ - any variable, or parameter referring to a distributed actor instance (regardless if remote or local),
+- _known-to-be-local distributed actor_, or "_distributed local actor_" for short - a specific known to be local instance of a distributed actor. A distributed actor reference can be checked at runtime if it is remote or local, but in certain situations it is also known in the type system that an actor is "definitely local" and not all isolation checks need to be applied,
+- "_distributed remote actor_" - an instance of a distributed actor type, that is actually "remote" and therefore does not have any storage allocated and effectively functions like a "proxy" object. This state does not exist anywhere explicitly in the type-system explicitly, and is what we assume every distributed actor is, unless proven to be "known to be local".
+
+Keeping this in mind, let us proceed to discussing the specific isolation rules of distributed actors.
+
+## Proposed solution
+
+### Distributed Actors
+
+Distributed actors are a flavor of the `actor` type that enforces additional rules on the type and its instances in order to enable location transparency. Thanks to this, it is possible to program against a `distributed actor` without *statically* knowing if a specific instance is remote or local. All calls are made to look as-if they were remote, and in the local case simply no networking s performed and the calls execute the same as if they were a normal local-only actor.
+
+Distributed actors are declared by prepending `distributed` to an `actor` declaration:
+
+```swift
+distributed actor Player {
+ // ...
+ let name: String
+}
+```
+
+While we do not deep dive into the runtime representation in this proposal, we need to outline the general idea behind them: a `distributed actor` is used to represent an actor which may be either *local* or *remote*.
+
+This property of hiding away information about the location of the actual instance is called _location transparency_. Under this model, we must program against such location transparent type as-if it was remote, even when it might not be. This allows us to develop and test distributed algorithms locally, without having to resort to networking (unless we want to), vastly simplifying the testing of such systems.
+
+> **Note:** This is not the same as making "remote calls look like local ones" which has been a failure of many RPC systems. Instead, it is the opposite! Pessimistically assuming that all calls made cross-actor to a distributed actor may be remote, and offering specific ways to guarantee that some calls are definitely local (and thus have the usual, simpler isolation rules).
+
+Distributed actor isolation checks introduced by this proposal serve the purpose of enforcing the property of location transparency, and helping developers not accidentally break it. For example, the above `Player` actor could be used to represent an actor in a remote host, where the same game state is stored and references to player's devices are managed. As such, the _state_ of a distributed actor is not known locally. This brings us to the first of the additional isolation checks: properties.
+
+### Complete isolation of state
+
+Because a distributed actor, along with its actual state, may be located on a remote host, some conveniences local-only actors allow cannot be allowed for distributed ones. Let's consider the following `Player` type:
+
+```swift
+public distributed actor Player {
+ public let name: String
+ public var score: Int
+}
+```
+
+Such actor may be running on some remote host, meaning that if we have a "remote reference" to it we _do not_ have its state available, and any attempt to get it would involve network communication. Because of that, stored properties are not accessible across distributed actors:
+
+```swift
+let player: Player = // ... get remote reference to Player
+player.name // ❌ error: distributed actor state is only available within the actor instance
+```
+
+Developers should think carefully about operations that cross into the actor's isolation domain, because the cost of each operation can be very expensive (e.g., if the actor is on a machine across the internet). Properties make it very easy to accidentally make multiple round-trips:
+
+```swift
+func example1(p: Player) async throws -> (String, Int) {
+ try await (p.name, p.score) // ❌ might make two slow network round-trips to `p`
+}
+```
+
+Instead, the use of methods to perform a batched read is strongly encouraged.
+
+Stored properties can only be accessed when the actor is known-to-be-local, a property that is possible to check at runtime using the `whenLocal` function that we'll discuss later during this proposal. The following snippet illustrates one example of such known-to-be-local actor access, though there can be different situations where this situation occurs:
+
+```swift
+distributed actor Counter {
+ var count = 0
+
+ func publishNextValue() {
+ count += 1
+ Task.detached { @MainActor in
+ ui.countLabel.text = "Count is now \(await self.count)"
+ }
+ }
+}
+```
+
+Stored properties cannot be declared `distributed` nor `nonisolated`. Computed properties however can be either of the two. However, computed properties can only be `distributed` if they are `get`-only due to limitations in how effectful properties work, in which case they function effectively the same as distributed methods which we'll discuss next.
+
+### Distributed Methods
+
+In order to enforce the distributed "*maybe remote*" nature of distributed actors, this proposal introduces a new flavor of method declaration called a *distributed method*. Other than a few special cases (such as `nonisolated` members), distributed methods are the only members that can be invoked cross-actor on distributed actors.
+
+It is necessary to give developers tight control over the distributed nature of methods they write, and it must be a conscious opt-in step. It is also possible to declared computed properties as `distributed`. A distributed method or property is defined within a distributed actor type by writing `distributed` in front of the method's declaration:
+
+```swift
+distributed actor Player {
+
+ distributed func yourTurn() -> Move {
+ return thinkOfNextMove()
+ }
+
+ func thinkOfNextMove() -> Move {
+ // ...
+ }
+
+ distributed var currentTurn: Int {
+ // ...
+ }
+}
+```
+
+It is not possible to invoke the `thinkOfNextMove()` method cross-actor, because the target of the invocation may be remote, and it was not "exposed" for distribution using the `distributed func` keywords. This is checked at compile time and is a more restrictive form of actor-isolation checking:
+
+```swift
+func test(p: Player) async throws {
+ try await p.yourTurn()
+ // ✅ ok, distributed func
+
+ try await p.currentTurn
+ // ✅ ok, distributed computed property
+
+ try await p.thinkOfNextMove()
+ // ❌ error: only 'distributed' instance methods can be called on a potentially remote distributed actor
+}
+```
+
+Distribution must not be simply inferred from access-control, because the concept of distribution is orthogonal to access control. For example, it is very much common to have `internal distributed func` (or even `private distributed func`) declarations, which are useful for actors within a module communicating with each other (remotely), however those methods should be invoked be end-users of such library.
+
+Distributed methods may be subject to additional type-checking, specifically a distributed actor infers a `SerializationRequirement` from the ActorSystem it is associated with. One common serialization requirement is `Codable`.
+
+Such `SerializationRequirement` typealias defined on the actor system the actor is associated with causes additional type-checks to be enforced on distributed methods: all parameter types and return type of such method must be or conform to the SerializationRequirement type. This allows the compiler to fail compilation early, rather than leaving serialization crashes to the runtime, easing development and analysis of distributed actor systems:
+
+```swift
+distributed actor Player {
+ typealias ActorSystem = CodableMessagingSystem
+ // inferred: typealias SerializationRequirement = Codable
+
+ distributed func test(not: NotCodable) {}
+ // ❌ error: parameter 'not' of type 'NotCodable' in distributed instance method
+ // does not conform to 'Codable'
+}
+```
+
+
+
+## Detailed design
+
+Unless otherwise specified in this proposal, the semantics of a distributed actor are the same as a regular actor, as described in [SE-0306](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0306-actors.md).
+
+### Distributed Actors
+
+Distributed actors can only be declared using the `distributed actor` keywords. Such types automatically conform to the `DistributedActor` protocol. The protocol is defined in the `_Distributed` module as follows:
+
+```swift
+/// Common protocol to which all distributed actors conform.
+///
+/// The `DistributedActor` protocol generalizes over all distributed actor types.
+/// All distributed actor types implicitly conform to this protocol.
+///
+/// It is not possible to explicitly conform to this protocol using any other declaration
+/// other than a 'distributed actor', e.g. it cannot be conformed to by a plain 'actor' or 'class'.
+///
+/// ### Implicit Codable conformance
+/// If the 'ID' conforms to `Codable` then the concrete distributed actor adopting this protocol
+/// automatically gains a synthesized Codable conformance as well. This is because the only reasonable
+/// way to implement coding of a distributed actor is to encode it `ID`, and decoding can make use of
+/// decoding the same ID, and resolving it using an actor system found in the Decoder's `userInfo`.
+///
+/// This works well with `Codable` serialization requirements, and allows actor references to be
+/// sent to other distributed actors.
+protocol DistributedActor: AnyActor, Identifiable, Hashable
+ where ID == ActorSystem.ActorID {
+
+ /// Type of the distributed actor system this actor is able to operate with.
+ /// It can be a type erased, or existential actor system (through a type-eraser wrapper type),
+ /// if the actor is able to work with different ones.
+ associatedtype ActorSystem: DistributedActorSystem
+
+ /// The serialization requirement to apply to all distributed declarations inside the actor.
+ typealias SerializationRequirement = ActorSystem.SerializationRequirement
+
+ /// Unique identity of this distributed actor, used to resolve remote references to it from other peers,
+ /// and also enabling the Hashable and (optional) Codable conformances of a distributed actor.
+ ///
+ /// The id may be freely shard across tasks and processes, and resolving it should return a reference
+ /// to the actor where it originated from.
+ nonisolated override var id: ID { get }
+
+ /// Distributed Actor System responsible for managing this distributed actor.
+ ///
+ /// It is responsible for assigning and managing the actor's id,
+ /// as well as delivering incoming messages as distributed method invocations on the actor.
+ nonisolated var actorSystem: ActorSystem { get }
+}
+```
+
+All distributed actors are *explicitly* part of some specific distributed actor system. The term "actor system" originates from both early, and current terminology relating to actor runtimes and loosely means "group of actors working together", which carries a specific meaning for distributed actors, because it implies they must be able to communicate over some (network or ipc) protocol they all understand. In Swift's local-only actor model, the system is somewhat implicit, because it simply is "the runtime", as all local objects can understand and invoke each other however they see fit. In distribution this needs to become a little more specific: there can be different network protocols and "clusters" to which actors belong, and as such, they must be explicit about their actor system use. We feel this is an expected and natural way to introduce the concept of actor systems only once we enter distribution, because previously (in local only actors) the concept would not have added much value, but in distribution it is the *core* of everything distributed actors do.
+
+The protocol also includes two nonisolated property requirements: `id` and `actorSystem`. Witnesses for these requirements are nonisolated computed properties that the compiler synthesizes in specific distributed actor declarations. They store the actor system the actor was created with, and its id, which is crucial to its lifecycle and messaging capabilities. We will not discuss in depth how the id is assigned in this proposal, but in short: it is created and assigned by the actor system during the actor's initialization.
+
+Note, that the `DistributedActor` protocol does *not* refine the `Actor` protocol, but instead it refines the `AnyActor` protocol, also introduced in this proposal. This detail is very important to upholding the soundness of distributed actor isolation.
+
+Sadly, just refining the Actor protocol results in the following unsound isolation behavior:
+
+```swift
+// Illustrating isolation violation, IF 'DistributedActor' were to refine 'Actor':
+extension Actor {
+ func f() -> SomethingSendable { ... }
+}
+func g(a: A) async {
+ print(await a.f())
+}
+
+// given any distributed actor:
+actor MA: DistributedActor {} // : Actor implicitly (not proposed, for illustration purposes only)
+
+func h(ma: MA) async {
+ await g(ma) // 💥 would be allowed because a MA is an Actor, but can't actually work at runtime
+}
+```
+
+The general issue here is that a distributed actor type must uphold its isolation guarantees, because the actual instance of such type may be remote, and therefore cannot be allowed to have non-distributed calls made on it. One could argue for the inverse relationship, that `Actor: DistributedActor` as the Actor is more like "`LocalActor`", however this idea also breaks down rather quickly, as one would expect "any IS-A distributed actor type, to have distributed actor isolation", however we definitely would NOT want `actor Worker {}` suddenly exhibit distributed actor isolation. In a way, this way of inheritance breaks the substitution principle in weird ways which could be hacked together to make work, but feel fragile and would lead to hard to understand isolation issues.
+
+In order to prevent this hole in the isolation model, we must prevent `DistributedActor` from being downcast to `Actor` and the most natural way of doing so, is introducing a shared super-type for the two Actor-like types: `AnyActor`.
+
+```swift
+@_marker
+@available(SwiftStdlib 5.6, *)
+public protocol AnyActor: Sendable, AnyObject {}
+
+public protocol Actor: AnyActor { ... }
+public protocol DistributedActor: AnyActor, ... { ... }
+```
+
+Thanks to this protocol we gain an understandable, and complete, type hierarchy for all actor-like behaviors, that is, types that perform a kind of isolation checking and guarantee data-race freedom to invocations on them by serializing them through an actor mailbox. This does not incur much implementation complexity in practice because functionality wise, distributed actors mirror actors exactly, however their customization of e.g. executors only applies to local instances.
+
+## Distributed Actor Systems
+
+Libraries aiming to implement distributed actor systems, and act as the runtime for distributed actors must implement the `DistributedActorSystem`. We will expand the definition of this protocol with important lifecycle functions in the runtime focused proposal, however for now let us focus on its aspects which affect type checking and isolation of distributed actors. The protocol is defined as:
+
+```swift
+public protocol DistributedActorSystem: Sendable {
+ associatedtype ActorID: Hashable & Sendable // discussed below
+
+ /// The serialization requirement that will be applied to all distributed targets used with this system.
+ typealias SerializationRequirement = // (simplified, actually an associatetype)
+
+ // ... many lifecycle related functions, to be defined in follow-up proposals ...
+}
+```
+
+Every distributed actor must declare what distributed actor system it is able to work with, this is expressed as an `associatedtype` requirement on the `DistributedActor` protocol, to which all `distributed actor` declarations conform implicitly. For example, this distributed actor works with some `ClusterSystem`:
+
+```swift
+distributed actor Worker {
+ typealias ActorSystem = ClusterSystem
+}
+```
+
+The necessity of declaring this statically will become clear as we discuss the serialization requirements and details of the typechecking mechanisms in the sections below.
+
+Please note that it is possible to use a protocol or type eraser as the actor system, which allows actors to swap-in completely different actor system implementations, as long as their serialization mechanisms are compatible. Using existential actor systems though comes at a slight performance penalty (as do all uses of existentials).
+
+It is possible to declare a module-wide `typealias DefaultDistributedActorSystem` in order to change this "default" actor system type, for all distributed actor types declared within a module:
+
+```swift
+// in 'Cluster' module:
+typealias DefaultDistributedActorSystem = ClusterSystem
+
+// in 'Cluster' module, clearly we want to use the 'ClusterSystem'
+distributed actor Example {
+ // synthesized:
+ // typealias DistributedActorSystem = DefaultDistributedActorSystem // ClusterSystem
+
+ // synthesized initializers (discussed below) also accept the expected type then:
+ // init(system: DefaultDistributedActorSystem) { ... }
+}
+```
+
+It is also possible to declare protocols which refine the general `DistributedActor` concept to some specific transport, such as:
+
+```swift
+protocol ClusterActor: DistributedActor where DistributedActorSystem == ClusterSystem {}
+
+protocol XPCActor: DistributedActor where DistributedActorSystem == XPCSystem { }
+```
+
+Those protocols, because they refine the `DistributedActor` protocol, can also only be conformed to by other distributed actors. It allows developers to declare specific requirements to their distributed actor's use, and even provide extensions based on the actor system type used by those actors, e.g.:
+
+```swift
+extension DistributedActor where DistributedActorSystem == ClusterSystem {
+ /// Returns the node on which this distributed actor instance is located.
+ nonisolated var node: Cluster.Node? { ... }
+}
+```
+
+> **Note:** We refer to `distributed actor` declarations or protocols refining the `DistributedActor` protocol as any "distributed actor type" - wherever this phrase is used, it can apply to a specific actor or such protocol.
+
+### Distributed Actor Initializers
+
+Distributed actor initializers are always _local_, therefore no special rules are applied to their isolation checking.
+
+Distributed actor initializers are subject to the same isolation rules as actor initializers, as outlined in [SE-0327: On Actors and Initialization](https://forums.swift.org/t/se-0327-on-actors-and-initialization/53053). Please refer to that proposal for details about when it is safe to escape `self` out of an actor initializer, as well as when it is permitted to call other functions on the actor during its initialization.
+
+A distributed actor's *designated initializer* must always contain exactly one `DistributedActorSystem` parameter. This is because the lifecycle and messaging of a distributed actor is managed by the system. It also assigns every newly initialized distributed actor instance an identity, that the actor then stores and makes accessible via the compiler-synthesized computed property `id`. The system is similarly available to the actor via the compiler synthesized computed property `actorSystem`.
+
+Similar to classes and local-only actors, a distributed actor gains an implicit default designated initializer when no user-defined initializer is found. This initializer accepts an actor system as parameter, in order to conform to the requirement stated above:
+
+```swift
+// default system for this module:
+typealias DefaultDistributedActorSystem = SomeSystem
+
+distributed actor Worker {
+ // synthesized default designated initializer:
+ // init(system: DefaultDistributedActorSystem)
+}
+```
+
+if no module-wide `DefaultDistributedActorSystem` is defined, such declaration would request the developer to provide one at compile time:
+
+```swift
+distributed actor Worker {
+ typealias ActorSystem = SomeSystem
+
+ // synthesized default designated initializer:
+ // init(system: SomeSystem)
+}
+```
+
+Alternatively, we can infer this typealias from a user-defined initializer, like this:
+
+```swift
+distributed actor Worker {
+ // inferred typealias from explicit initializer declaration
+ // typealias ActorSystem = SomeSystem
+
+ init(system: SomeSystem) { self.name = "Alice" }
+}
+```
+
+The necessity to pass an actor system to each newly created distributed actor is because the system is the one assigning and managing identities. While we don't discuss those details in depth in this proposal, here is a short pseudocode of why passing this system is necessary:
+
+```swift
+// Lifecycle interactions with the system during initialization
+// NOT PART OF THIS PROPOSAL; These will be discussed in-depth in a forthcoming proposal focused on the runtime.
+distributed actor Worker {
+ init(system: SomeSystem) {
+ // self._system = system
+ // the actor is assigned an unique identity as it initializes:
+ // self._id = system.assignID(Self.self)
+ self.name = "Alice"
+ // once fully initialized, the actor is ready to receive remote calls:
+ // system.actorReady(self)
+ }
+}
+```
+
+Having that said, here are a few example of legal and illegal initializer declarations:
+
+```swift
+distributed actor InitializeMe {
+ init()
+ // ❌ error: designated distributed actor initializer 'init()' is missing required 'DistributedActorSystem' parameter
+
+ init(x: String)
+ // ❌ error: designated distributed actor initializer 'init(x:)' is missing required 'DistributedActorSystem' parameter
+
+ init(system: AnyDistributedActorSystem, too many: AnyDistributedActorSystem)
+ // ❌ error: designated distributed actor initializer 'init(system:too:)' must accept exactly one DistributedActorSystem parameter, found 2
+
+ // --------
+
+
+ init(system: AnyDistributedActorSystem) // ✅ ok
+ init(y: Int, system: AnyDistributedActorSystem) // ✅ ok
+ init(canThrow: Bool, system: AnyDistributedActorSystem) async throws // ✅ ok, effects are ok too
+
+ // 'convenience' may or may not be necessary, depending on SE-0327 review outcome.
+ convenience init() {
+ self.init(system: SomeSystem(...)) // legal, but not recommended
+ }
+}
+```
+
+*Remote* distributed actor references are not obtained via initializers, but rather through a static `resolve(_:using:)` function that is available on any distributed type:
+
+```swift
+extension DistributedActor {
+
+ /// Resolves the passed in `id` using the passed distributed actor `system`,
+ /// returning either a local or remote distributed actor reference.
+ ///
+ /// The system will be asked to `resolve` the identity and return either
+ /// a local instance or request a "proxy" to be created for this identity.
+ ///
+ /// A remote distributed actor reference will forward all invocations through
+ /// the system, allowing it to take over the remote messaging with the
+ /// remote actor instance.
+ ///
+ /// - Parameter id: identity uniquely identifying a, potentially remote, actor in the system
+ /// - Parameter system: distributed actor system which must resolve and manage the returned distributed actor reference
+ static func resolve(id: ID, using system: DistributedActorSystem) throws -> Self
+}
+```
+
+The specifics of resolving, and remote actor runtime details will be discussed in a follow-up proposal focused on the runtime aspects of distributed actors. We mention it here to share a complete picture how Identities, systems, and remote references all fit into the picture.
+
+### Distributed Actors implicitly conform to Codable
+
+If a distributed actor's `ID` conforms to `Codable`, the distributed actor automatically gains a `Codable` conformance as well.
+
+This conformance is synthesized by the compiler, for every specific `distributed actor` declaration. It is not possible to express such conformance using the conditional conformances.
+
+> **Note:** It is not possible to implement such conformance semantics on the DistributedActor protocol using conditional conformances (like this `extension DistributedActor: Codable where ID: Codable`), and it is unlikely to be supported in the future. As such, we currently opt to synthesize the conformance for specific distributed actor declarations.
+
+```swift
+distributed actor Player /*: DistributedActor, Codable */ {
+ // typealias ID = SomeCodableID
+}
+```
+
+The synthesized `Codable` conformance strictly relies on the implementation of the actors' identity `Codable` conformance. When we "encode" a distributed actor, we never encode "the actor", but rather only its identity:
+
+```swift
+// distributed actor Player: Codable, ... {
+ nonisolated public func encode(to encoder: Encoder) throws {
+ var container = encoder.singleValueContainer()
+ try container.encode(self.id)
+ }
+// }
+```
+
+And similarly, decoding a distributed actor has the specific meaning of attempting to `resolve(_:using:)` a reference of the specific actor type, using the decoded id:
+
+```swift
+// distributed actor Player: Codable, ... {
+ nonisolated public init(from decoder: Decoder) throws {
+ // ~~~ pseudo code for illustration purposes ~~~
+ guard let system = decoder.userInfo[.distributedActorSystemKey] as? Self.ActorSystem else {
+ throw DistributedActorCodingError(message:
+ "Missing DistributedActorSystem (for key .distributedActorSystemKey) " +
+ "in \(decoder).userInfo, while decoding \(Self.self)!")
+ }
+
+ // [1] decode the identity
+ let id: ID = try Self.ID(from: decoder)
+ // [2] resolve the identity using the current system; this usually will return a "remote reference"
+ self = try Self.resolve(id: id, using: system) // (!)
+ }
+// }
+```
+
+The Decodable's `init(from:)` implementation is actually not possible to express in plain Swift today, because the restriction on self assignment in class initializers (and therefore also actor initializers).
+
+> **Note:** We could eventually generalize this more mutable `self` in class/actor initializer mechanism, however that would be done as separate Swift Evolution proposal. We are aware [this feature was requested before](https://forums.swift.org/t/allow-self-x-in-class-convenience-initializers/15924), and feels like a natural follow up to this proposal to generalize this capability.
+
+Note also that, realistically, there is only one correct way to implement a distributed actor's codability (as well as `Hashable` and `Equatable` conformances), because the only property that is related to its identity, and is known to both local and remote "sides" is the identity, as such implementations of those protocols must be directly derived from the `id` property of a distributed actor.
+
+The capability, to share actor references across to other (potentially remote) distributed actors, is crucial for location-transparency and the ability to "send actor references around" which enables developers to implement "call me later" style patterns (since we cannot do so with closures, as they are not serializable). In a way, this is similar to the delegate pattern, known to developers on Apple platforms: where we offer an instance to some other object, that will call lifecycle or other types of methods on the delegate whenever certain events happen.
+
+To illustrate how this capability is used in practice, let us consider the following turn-based distributed `Game` example, which waits until it has enough players gathered, and then kicks off the game by notifying all the players (regardless _where_ they are located) that the game is now starting.
+
+```swift
+typealias DefaultDistributedActorSystem = SomeCodableDistributedActorSystem
+struct SomeCodableDistributedActorSystem: DistributedActorSystem {
+ typealias ActorID = SomeCodableID
+ typealias SerializationRequirement = Codable
+}
+
+distributed actor Player {
+ distributed func play(turn: Int) -> Move { ... }
+ distributed func opponentMoved(_ move: Move) { ... }
+}
+
+distributed actor Game {
+ let minPlayers = 2
+ var players: Set = []
+
+ distributed func join(player: Player) async throws {
+ guard players.count < 2 else {
+ throw ...
+ }
+
+ players.insert(player)
+
+ if players.count == 2 {
+ await play() // keep asking players for their move via 'play(turn:)' until one of them wins
+ }
+ }
+
+ func play() async throws {
+ // keep asking players for their move via 'play(turn:)' until one of them wins
+ }
+
+ distributed var result: GameResult {
+ ...
+ }
+}
+
+func play(game: Game) async throws {
+ try await game.join(player: Player(system: ...))
+ try await game.join(player: Player(system: ...))
+ // the game begins, players are notified about it
+
+ let result = try await game.result
+ print("Winner of \(game) was: \(result.winner)")
+}
+```
+
+The `Player` distributed actor automatically gained a Codable conformance, because it is using the `SomeCodableDistributedActorSystem` that assigns it a `SomeCodableID`. Other serialization mechanisms are also able to implement this "encode the ID" and "decode the ID, and resolve it" pattern, so this pattern is equally achievable using Codable, or other serialization mechanisms.
+
+### Distributed Methods
+
+The primary way a distributed actor can be interacted with are distributed methods. Most notably, invoking a non-distributed method (i.e. those declared with *just* the `func` keyword by itself), is not allowed as it may be potentially violating distributed actor isolation rules, that is unless the target of the invocation is known to be a *local* distributed actor - a topic we'll explore later on in this proposal:
+
+```swift
+distributed actor IsolationExample {
+ func notDistributed() {}
+ distributed func accessible() {}
+ distributed var computed: String { "" }
+}
+
+func test(actor: IsolationExample) async throws {
+ try await actor.notDistributed()
+ // ❌ error: only 'distributed' instance methods can be called on a potentially remote distributed actor
+
+ try await actor.accessible()
+ // ✅ ok, method is distributed
+
+ try await actor.computed
+ // ✅ ok, distributed get-only computed property
+}
+```
+
+Distributed methods are declared by writing the `distributed` keyword in the place of a declaration modifier, under the `actor-isolation-modifier` production rule as specified by [the grammar in TSPL](https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#grammar_declaration-modifiers). Only methods can use `distributed` as a declaration modifier, and no order is specified for this modifier.
+
+It is also possible to declare distributed get-only properties, and they obey the same rules as a parameter-less `distributed func` would. It is not permitted to make get/set computed properties, or stored properties `distributed`.
+
+Distributed actor types are the only types in which a distributed method declaration is allowed. This is because, in order to implement a distributed method, an actor system and identity must be associated with the values carrying the method. Distributed methods can synchronously refer to any of the state isolated to the distributed actor instance.
+
+The following distributed method declarations are not allowed:
+
+```swift
+actor/class/enum/struct NotDistributedActor {
+ distributed func test() {}
+ // ❌ error: 'distributed' function can only be declared within 'distributed actor'
+}
+
+protocol NotDistributedActorProtocol {
+ distributed func test()
+ // ❌ error: 'distributed' function can only be declared within 'distributed actor'
+ // 💡 fixit: add ': DistributedActor' to protocol inheritance clause
+}
+```
+
+While these are all proper declarations:
+
+```swift
+distributed actor Worker {
+ distributed func work() { ... }
+}
+
+extension Worker {
+ distributed func reportWorkedHours() -> Duration { ... }
+}
+
+protocol TypicalGreeter: DistributedActor {
+ distributed func greet()
+}
+```
+
+The last example, the `TypicalGreeter` protocol, can *only* be implemented by a `distributed actor`, because of the `DistributedActor` requirement. We will discuss distributed actors conforming to protocols in great detail below.
+
+It is not allowed to combine `distributed` with `nonisolated`, as a distributed function is _always_ isolated to the actor in which it is defined.
+
+```swift
+distributed actor Charlie {
+ distributed nonisolated func cantDoThat() {}
+ // ❌ error: 'distributed' function must not be 'nonisolated'
+ // 💡 fixit: remove 'nonisolated' or 'distributed'
+}
+```
+
+It is possible to declare a nonisolated method though. Such function can only access other `nonisolated` members of the instance. Two important members which are such nonisolated computed properties are the actor's identity, and associated actor system. Those are synthesized by the compiler, however they just follow the same isolation rules as laid out in this proposal:
+
+```swift
+distributed actor Charlie: CustomStringConvertible {
+ // synthesized: nonisolated var id: Self.ID { get }
+ // synthesized: nonisolated var actorSystem: Self.ActorSystem { get }
+
+ nonisolated var description: String {
+ "Charlie(\(self.id))" // ok to refer to `self.id` since also nonisolated
+ }
+}
+```
+
+Distributed methods may be declared explicitly `async` or `throws` and this has the usual effect on the declaration and method body. It has no effect on cross distributed actor calls, because such calls are implicitly asynchronous and throwing to begin with.
+
+The `distributed` nature of a method is completely orthogonal to access control. It is even possible to declare a `private distributed func` because the following pattern may make it an useful concept to have:
+
+```swift
+distributed actor Robot {
+
+ nonisolated async throws isHuman(caller: Caller) -> String {
+ guard isTrustworthy(caller) else {
+ return "It is a mystery!" // no remote call needs to be performed
+ }
+
+ return try await self.checkHumanity()
+ }
+
+ private distributed func checkHumanity() -> String {
+ "Human, after all!"
+ }
+}
+```
+
+Such methods allow us avoiding remote calls if some local validation already can short-circuit them. While not a common pattern, it definitely can have its uses. Note that the ability to invoke distributed methods remotely, also directly translates into such methods being "effectively public", even if access control wise they are not. This makes sense, and distributed methods must always be audited and carefully checked if they indeed should be allowed to execute when invoked remotely, e.g. they may need to perform caller authentication – a feature we do not provide out of the box yet, but are definitely interested in exploring in the future.
+
+It is not allowed to declare distributed function parameters as `inout` or varargs:
+
+```swift
+distributed actor Charlie {
+ distributed func varargs(int: Int...) {}
+ // ❌ error: cannot declare variadic argument 'int' in distributed instance method 'varargs(int:)'
+
+ distributed func noInout(inNOut burger: inout String) {}
+ // ❌ error: cannot declare 'inout' argument 'burger' in distributed instance method 'noInout(inNOut:)'
+ // 💡 fixit: remove 'inout'
+}
+```
+
+While subscripts share many similarities with methods, they can lead to complex and potentially impossible to support invocations, meaning that they are currently also not allowed to be `distributed`. Such subscripts' usefulness would, in any case, be severely limited by both their lack of support for being `async` (e.g., could only support read-only subscripts, because no coroutine-style accessors) and their lightweight syntax can lead to the same problems as properties.
+
+Distributed functions _may_ be combined with property wrappers to function parameters (which were introduced by [SE-0293: Extend Property Wrappers to Function and Closure Parameters](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0293-extend-property-wrappers-to-function-and-closure-parameters.md)), and their semantics are what one would expect: they are a transformation on the syntactical level, meaning that the actual serialized parameter value is what the property wrapper has wrapped the parameter in. This is especially interesting for implementing eager validation of specific parameters, such that calls with illegal argument values can be synchronously prevented before even sending the message. Of course, the recipient should still validate the incoming arguments using the same logic, but thanks to this we are able to avoid sending wrong values in non-adversarial situations, and just validate some values on the client side eagerly.
+
+#### Distributed Method Serialization Requirements
+
+An important goal of the distributed actor design is being able to enforce some level of compile time safety onto distributed methods calls, which helps prevent unexpected runtime failures, and aides developers make conscious decisions which types should be exposed to remote peers and which not.
+
+This feature is applied to `distributed` methods, and configured by declaring a `SerializationRequirement` typealias on the actor system, from which specific actors infer it. This type alias informs the type-checker to ensure that all parameters, as well as return type of distributed methods must conform to the type that is provided as `SerializationRequirement`. This is in addition to the usual `Sendable` conformance requirements enforced on any values passed to/from actors).
+
+Another interesting capability this unlocks is being able to confine actors to sending only well-known types, if we wanted to enforce such closed-world assumptions onto the permissible messages exchanged between actors.
+
+Most frequently, the serialization requirement is going to be `Codable`, so for the rest of this proposal we'll focus mostly on this use-case. It is equally possible and supported to provide e.g. an external serialization systems top-level protocol as requirement here, e.g. a Protocol Buffer `Message`. The following snippet illustrates how this can work in practice:
+
+```swift
+protocol CodableDistributedActorSystem: DistributedActorSystem {
+ typealias SerializationRequirement = Codable
+}
+
+distributed actor Worker {
+ typealias ActorSystem = CodableDistributedActorSystem
+ typealias SerializationRequirement = SpecificActorSystem.SerializationRequirement
+ // = Codable
+}
+```
+
+It is possible, albeit not recommended, to disable this checking by setting the `SerializationRequirement` to `Any` in which case no additional checks are performed on distributed methods.
+
+This section will discuss the implications of the `SerializationRequirement` on distributed method declarations.
+
+A serialization requirement means that all parameter types and return type of distributed method must conform to the requirement. With the `CodableDistributedActorSystem` in mind, let us write a few methods and see how this works:
+
+```swift
+distributed actor Worker {
+ typealias ActorSystem = CodableDistributedActorSystem
+
+ distributed func ok() // ✅ ok, no parameters
+ distributed func greet(name: String) -> String // ✅ ok, String is Codable
+
+ struct NotCodable {}
+
+ distributed func reject(not: NotCodable)
+ // ❌ error: parameter 'not' of type 'NotCodable' in distributed instance method
+ // does not conform to 'Codable'
+ // 💡 fixit: add ': Codable' to 'struct NotCodable'
+}
+```
+
+This also naturally extends to closures without any the need of introducing any special rules, because closures do not conform to protocols (such as `Codable`), the following is naturally ill-formed and rejected:
+
+```swift
+distributed actor Worker {
+ typealias ActorSystem = CodableDistributedActorSystem
+
+ distributed func take(_ closure: (String) -> String)
+ // ❌ error: parameter 'closure' of type '(String) -> String' in distributed instance method
+ // does not conform to 'Codable'
+}
+```
+
+Thrown errors are not enforced to be `Codable`, however a distributed actor system may detect that an error is Codable at runtime, and attempt to transfer it back entirely. For throws of non-Codable types, systems should attempt some form of best-effort description of the error, while keeping in mind privacy of error descriptions. I.e. errors should never be sent back to the caller by just getting their description, as that may leak sensitive information from the server system. A recommended approach here is to send back the type of the thrown error and throwing some generic `NotCodableError("\(type(of: error))")` or similar.
+
+Distributed actors may also witness protocol requirements (discussed in more detail below), however their method declarations must then also conform to the `SerializationRequirement`:
+
+```swift
+protocol Greetings {
+ func greet(name: String) async throws
+ func synchronous()
+}
+
+distributed actor Greeter: Greetings {
+ // typealias SerializationRequirement = Codable
+ distributed func greet(name: String) { // may or may not be async/throws, it always is when cross-actor
+ // ✅ ok, String is Codable
+ }
+
+ nonisolated func synchronous() {} // nonisolated func may be used the same as on normal actors
+}
+```
+
+Note that while every `distributed actor` must be associated with some specific distributed actor system, protocols need not be so strict and we are allowed to specify a distributed actor protocol like this:
+
+```swift
+protocol Greetings: DistributedActor {
+ // no specific ActorSystem requirement (!)
+ func greet(name: String)
+}
+```
+
+At the declaration site of such protocol the distributed functions are *not* subject to any `SerializationRequirement` checks. However once it is implemented by a distributed actor, that actor will be associated with a specific actor system, and thus also a specific SerializationRequirement, and could potentially not be able to implement such protocol because of the serializability checks, e.g.:
+
+```swift
+protocol Greetings: DistributedActor {
+ // no specific ActorSystem requirement (!)
+ func greet(name: String)
+}
+
+distributed actor Greeter {
+ // typealias SerializationRequirement = MagicMessage
+ distributed func greet(name: String) {}
+ // ❌ error: parameter 'name' of type 'String' in distributed instance method
+ // does not conform to 'MagicMessage'
+}
+```
+
+A similar mechanism will exist for resolving remote actor references only based on a protocol.
+
+#### Distributed Methods and Generics
+
+It is possible to declare and use distributed methods that make use of generics. E.g. we could define an actor that picks an element out of a collection, yet does not really care about the element type:
+
+```swift
+distributed actor Picker {
+ func pickOne- (from items: [Item]) -> Item? { // Is this ok? It depends...
+ ...
+ }
+}
+```
+
+This is possible to implement in general, however the `Item` parameter will be subject to the same `SerializableRequirement` checking as any other parameter. Depending on the associated distributed actor system's serialization requirement, this declaration may fail to compile, e.g. because `Item` was not guaranteed to be `Codable`:
+
+```swift
+distributed actor Picker {
+ // typealias ActorSystem = CodableMessagingSystem
+ func pickOne
- (from items: [Item]) -> Item? { nil }
+ // ❌ error: parameter 'items' of type '[Item]' in distributed instance method
+ // does not conform to 'Codable'
+ // ❌ error: return type 'Item' in distributed instance method does not conform to 'Codable'
+
+ func pickOneFixed
- (from items: [Item]) -> Item?
+ where Item: Codable { nil } // ✅ ok, we declared that the generic 'Item' is 'Codable'
+}
+```
+
+This is the same rule about serialization requirements really, but spelled out explicitly.
+
+ The runtime implementation of such calls is more complicated than non-generic calls, and does incur a slight wire envelope size increase, because it must carry the *specific type identifier* that was used to perform the call (e.g. that it was invoked using the *specific* `struct MyItem: Item` and not just some item). Generic distributed function calls will perform the deserialization using the *specific type* that was used to perform the remote invocation.
+
+As with any other type involved in message passing, actor systems may also perform additional inspections at run time of the types and check if they are trusted or not before proceeding to decode them (i.e. actor systems have the possibility to inspect incoming message envelopes and double-check involved types before proceeding tho decode the parameters).
+
+It is also allowed to make distributed actors themselves generic, and it works as one would expect:
+
+```swift
+distributed actor Worker { // ✅ ok
+ func work() -> Item { ... }
+}
+```
+
+
+
+#### Distributed Methods and Existential Types
+
+It is worth calling out that due to existential types not conforming to themselves, it is not possible to just pass a `Codable`-conforming existential as parameter to distributed functions. It will result in the following compile time error:
+
+```swift
+protocol P: Codable {}
+
+distributed actor TestExistential {
+ typealias ActorSystem = CodableMessagingSystem
+
+ distributed func compute(s: String, i: Int, p: P) {}
+ // ❌ error: parameter 'p' of type 'P' in distributed instance method does not conform to 'Codable'
+}
+```
+
+The way to deal with this, as with usual local-only Swift programming, is to make the `P` existential generic, like this:
+
+```swift
+protocol P: Codable {}
+
+distributed actor TestExistential {
+ typealias ActorSystem = CodableMessagingSystem
+
+ distributed func compute(s: String, i: Int, p: Param) {}
+ // ✅ ok, the generic allows us getting access to the specific underlying type
+}
+```
+
+which will compile, and work as expected.
+
+#### Implicit effects on Distributed Methods
+
+Local-only actor methods can be asynchronous , throwing or both, however invoking them cross-actor always causes them to become implicitly asynchronous:
+
+```swift
+// Reminder about implicit async on actor functions
+actor Greeter {
+ func greet() -> String { "Hello!" }
+ func inside() {
+ greet() // not asynchronous, we're not crossing an actor boundary
+ }
+}
+
+Task {
+ await Greeter().hi() // implicitly asynchronous
+}
+```
+
+The same mechanism is extended to the throwing behavior of distributed methods. Distributed cross-actor calls may fail not only because of the remote side actively throwing an error, but also because of transport errors such as network issues or serialization failures. Therefore, distributed cross-actor calls also implicitly gain the throwing effect, and must be marked with `try` when called:
+
+```swift
+distributed actor Greeter {
+ distributed func greet() -> String { "Hello!" }
+
+ func inside() {
+ greet() // not asynchronous or throwing, we're inside the actual local instance
+ }
+}
+
+Task {
+ try await Greeter().greet() // cross-actor distributed function call: implicitly async throws
+}
+```
+
+It is also possible to declare distributed functions as either `throws` or `async` (or both). The implicitly added effect is a no-op then, as the function always was, respectively, throwing or asynchronous already.
+
+The following snippets illustrate all cases how effects are applied to distributed actor methods:
+
+```swift
+distributed actor Worker {
+ distributed func simple() {}
+ distributed func funcAsync() async {}
+ distributed func funcThrows() throws {}
+ distributed func funcAsyncThrows() async throws {}
+}
+```
+
+Cross distributed-actor calls behave similar to cross actor calls, in the sense that they gain those implicit effects. This is because we don't know if the callee is remote or local, and thus assume that it might be remote, meaning that there may be transport errors involved in the call, making the function call implicitly throwing:
+
+```swift
+func outside(worker: Worker) async throws {
+ // wrong invocation:
+ worker.simple()
+ // ❌ error: expression is 'async' but is not marked with 'await'
+ // ❌ error: call can throw but is not marked with 'try'
+ // 💡 note: calls to distributed instance method 'simple()' from outside of its actor context are implicitly asynchronous
+
+ // proper invocations:
+ try await worker.simple()
+ try await worker.funcAsync()
+ try await worker.funcThrows()
+ try await worker.funcAsyncThrows()
+}
+```
+
+These methods may be also be called from *inside* the actor, as well as on an `isolated` parameter of that actor type, without any implicit effects applied to them. This is the same idea applies that actor methods becoming implicitly asynchronous but only during cross-actor calls.
+
+```swift
+extension Worker {
+ distributed func inside() async throws {
+ self.simple()
+ await self.funcAsync()
+ try self.funcThrows()
+ try await self.funcAsyncThrows()
+ }
+}
+
+func isolatedFunc(worker: isolated Worker) async throws {
+ worker.simple()
+ await worker.funcAsync()
+ try worker.funcThrows()
+ try await worker.funcAsyncThrows()
+}
+```
+
+The isolated function parameter works because the only way to offer an `isolated Worker` to a function, is for a real local actor instance to offer its `self` to `isolatedFunc`, and because of that it is known that it is a real local instance (after all, only a real local instance has access to `self`).
+
+It is not allowed to declare `isolated` parameters on distributed methods, because distributed methods _must_ be isolated to the actor they are declared on. This can be thought of always using an `isolated self: Self` parameter, and in combination of a func only being allowed to be isolated to a single actor instance, this means that there cannot be another isolated parameter on such functions. Following this logic a `nonisolated func` declared on a distributed actor, _is_ allowed to accept `isolated` parameters, however such call will not be crossing process boundaries.
+
+It is also worth calling out the interactions with `Task` and `async let`. Their context may be the same asynchronous context as the actor, in which case we also do not need to cause the implicit asynchronous effect. When it is known the invocation is performed on an `isolated` distributed actor reference, we infer the fact that it indeed is "known to be local", and do not need to apply the implicit throwing effect either:
+
+```swift
+extension Worker {
+ func test(other: Philosopher) async throws {
+ // self --------------------------------------------------------------------
+ async let alet = self.simple() // implicitly async; async let introduced concurrent context
+ _ = await alet // not throwing, but asynchronous!
+
+ Task {
+ _ = self.hi() // no implicit effects, Task inherited the Actor's execution context
+ }
+
+ Task.detached {
+ _ = await self.hi() // implicitly async, different Task context than the actor
+ // however not implicitly throwing; we know there is no networking involved in a call on self
+ }
+
+ // other -------------------------------------------------------------------
+ async let otherLet = other.hi() // implicitly async and throws; other may be remote
+ _ = try await otherLet // forced to 'try await' here, as per usual 'async let' semantics
+
+ Task {
+ _ = try await other.hi() // implicitly async and throws
+ }
+
+ Task.detached {
+ _ = try await other.hi() // implicitly async and throws
+ }
+ }
+}
+```
+
+#### Isolation states and Implicit effects on Distributed Methods
+
+A distributed actor reference. such as a variable or function parameter, effectively can be in one of three states:
+
+- `isolated` – as defined by Swift's local-only actors. The `isolated` also implies the following "local" state, because it is not possible to pass isolated members across distributed boundaries,
+- "local" – not explicitly modeled in the type-system in this proposal, though we might end up wanting to do so (see Future Directions), or
+- "potentially remote" – which is the default state of any distributed actor variable.
+
+These states determine the implicit effects that function invocations, and general distributed actor isolation checking, need to apply when checking accesses through the distributed actor reference.
+
+Let us discuss the implications of these states on the effects applied to method calls on such distributed actor references, starting from the last "potentially remote" state, as it is the default and most prominent state which enables location-transparency.
+
+By default, any call on a ("potentially remote") distributed actor must be assumed to be crossing network boundaries. Thus, the type system pessimistically applies implicit throwing and async effects to such call-sites:
+
+```swift
+func test(actor: Greeter) async throws {
+ try await actor.greet(name: "Asa") // ✅ call could be remote
+}
+```
+
+In special circumstances, a reference may be "known to be local", even without introducing a special "local" keyword in the language this manifests itself for example in closures which capture `self`. For example, we may capture `self` in a detached task, meaning that the task's closure will be executing on some different execution context than the actor itself -- and thus `self` is *not* isolated, however we *know* that it definitely is local, because there is no way we could ever refer to `self` from a remote actor:
+
+```swift
+distributed actor Closer {
+ distributed func check() -> Bool { true }
+
+ func test() {
+ Task.detached {
+ await self.check() // ✅ call is definitely local, but it must be asynchronous
+ }
+ }
+}
+```
+
+In the above situation, we know for sure that the `self.check()` will not be crossing any process boundaries, and therefore there cannot be any implicit errors emitted by the underlying distributed actor system transport. This manifests in the type-system by the `distributed func` call not being throwing (!), however it remains asynchronous because of the usual local-only actor isolation rules.
+
+The last case is `isolated` distributed actor references. This is relatively simple, because it just reverts all isolation checking to the local-only model. Instance members of actors are effectively methods which take an `isolated Self`, and in the same way functions which accept an `isolated Some(Distributed)Actor` are considered to be isolated to that actor. For the purpose of distributed actor isolation checking it effectively means there are no distributed checks at all, and we can even access stored properties synchronously on such reference:
+
+```swift
+distributed actor Namer {
+ let baseName: String = ...
+}
+
+func bad(n: Namer) {
+ n.baseName // ❌ error, as expected we cannot access the distributed actor-isolated state
+}
+
+func good(n: isolated Namer) {
+ n.baseName // ✅ ok; we are isolated to the specific 'n' Namer instance
+}
+```
+
+### Distributed Actor Properties
+
+#### Stored properties
+
+Distributed actors may declare any kind of stored property, and the declarations themselves are *not restricted in any way*. This is important and allows distributed actors to store any kind of state, even if it were not serializable. Access to such state from the outside though is only allowed through distributed functions, meaning that cross-network access to such non-serializable state must either be fully encapsulated or "packaged up" into some serializable format that leans itself to transporting across the network.
+
+One typical example of this is a distributed actor storing a live database connection, and being unable to send this connection across to other nodes, it should send the results of querying the database to its callers. This is a very natural way to think about actor storage, and will even be possible to enforce at compile time, which we'll discuss in follow-up proposals discussing serialization and runtime aspects of distributed actor messages.
+
+To re-state the rule once again more concisely: It is not possible to reach a distributed actors stored properties cross-actor. This is because stored properties may be located on a remote host, and we do not want to subject them to the same implicit effects, and serialization type-checking as distributed methods.
+
+```swift
+distributed actor Properties {
+ let fullName: String
+ var age: Int
+}
+```
+
+Trying to access those properties results in isolation errors at compile time:
+
+```swift
+Properties().fullName
+// ❌ error: distributed actor-isolated property 'fullName' can only be referenced inside the distributed actor
+Properties().age
+// ❌ error: distributed actor-isolated property 'age' can only be referenced inside the distributed actor
+```
+
+Unlike with local-only actors, it is *not* allowed to declare `nonisolated` *stored properties*, because a nonisolated stored property implies the ability to access it without any synchronization, and would force the remote "proxy" instance to have such stored property declared and initialized, however there is no meaningful good way to initialize such variable, because a remote reference is _only_ the actor's identity and associated transport (which will be explored in more depth in a separate proposal):
+
+```swift
+distributed actor Properties {
+ nonisolated let fullName: String // ❌ error: distributed actor cannot declare nonisolated stored properties
+}
+```
+
+It is allowed to declare static properties on distributed actors, and they are not isolated to the actor. This is the same as static properties on local-only actors.
+
+```swift
+distributed actor Worker {
+ static let MAX_ITEMS: Int = 12 // ⚠️ static properties always refer to the value in the *local process*
+ var workingOnItems: Int = 0
+
+ distributed func work(on item: Item) throws {
+ guard workingOnItems < Self.MAX_ITEMS else {
+ throw TooMuchWork(max: Self.MAX_ITEMS)
+ }
+
+ workingonItems += 1
+ }
+}
+```
+
+Be aware though that any such `static` property on a `distributed actor` always refers to whatever the property was initialized with _locally_ (in the current process). i.e. if the remote node is running a different version of the software, it may have the `MAX_ITEMS` value set to something different. So keep this in mind when debugging code while rolling out new versions across a cluster. Static properties are useful for things like constants, so feel free to use them in the same manner as you would with local-only actors.
+
+It is permitted, same as with local-only actors, to declare `static` methods and even `static` variables on distributed actors, although please be advised that currently static variables are equally thread-*unsafe* as global properties and Swift Concurrency currently does not perform any checks on those.
+
+```swift
+// Currently allowed in Swift 5.x, but dangerous (for now)
+[distributed] actor Glass {
+ var contents: String = Glass.defaultContents
+
+ static var defaultContents: String { "water" } // ⚠️ not protected from data-races in Swift 5.x
+}
+```
+
+As such, please be very careful with such mutable declarations. Swift Concurrency will eventually also check for shared global and static state, and devise a model preventing races in such declarations as well. Static properties declared on distributed actors will be subject to the same checks as any other static properties or globals once this has been proposed and implemented (via a separate Swift Evolution proposal).
+
+#### Computed properties
+
+Distributed _computed properties_ are possible to support in a very limited fashion because of the effectful nature of the distributed keyword. It is only possible to make *read-only* properties distributed, because only such properties may be effectful (as introduced by [SE-0310: Effectful Read-only Properties](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0310-effectful-readonly-properties.md)).
+
+```swift
+distributed actor Chunk {
+ let chunk: NotSerializableDataChunk
+
+ distributed var size: Int { self.chunk.size }
+}
+```
+
+A distributed computed property is similar to a method accepting zero arguments, and returning a value.
+
+Distributed computed properties are subject to the same isolation rules, and implicit async and throwing effects. As such, accessing such variable (even across the network) is fairly explicitly telling the developer something is going on here, and they should re-consider if e.g. doing this in a loop truly is a good idea:
+
+```swift
+var i = 0
+while i < (try await chunk.size) { // very bad idea, don't do this
+ // logic here
+ i += 1
+}
+
+// better, only check the size once:
+var i = 0
+let max = try await chunk.size // implicitly 'async throws', same as distributed methods
+while i < max {
+ // logic here
+ i += 1
+}
+```
+
+Because distributed methods and properties are statically known, we could envision IDEs giving explicit warnings, and even do some introspection and analysis detecting such patterns if they really wanted to.
+
+Any value returned by such computed property needs to be able to be serialized, similarly to distributed method parameters and return values, and would be subject to the same checks.
+
+It is not possible to declare read/write computed properties, because of underlying limitations of effectful properties.
+
+### Protocol Conformances
+
+Distributed actors can conform to protocols in the same manner as local-only actors can.
+
+As calls "through" protocols are always cross-actor, requirements that are possible to witness by a `distributed actor` must be `async throws`. The following protocol shows a few examples of protocol requirements, and whether they are possible to witness using a distributed actor's distributed function:
+
+```swift
+protocol Example {
+ func synchronous()
+ func justAsync() async -> Int
+ func justThrows() throws -> Int
+ func asyncThrows() async throws -> String
+}
+```
+
+We can attempt to conform to this protocol using a distributed actor:
+
+```swift
+distributed actor ExampleActor: Example {
+ distributed func synchronous() {}
+ // ❌ error: actor-isolated instance method 'synchronous()' cannot be used to satisfy a protocol requirement
+ // cross-actor calls to 'justThrows()' are 'async throws' yet protocol requirement is synchronous
+
+ distributed func justAsync() async -> Int { 2 }
+ // ❌ error: actor-isolated instance method 'justAsync()' cannot be used to satisfy a protocol requirement
+ // cross-actor calls to 'justAsync()' are 'async throws' yet protocol requirement is only 'async'
+
+ distributed func justThrows() throws -> Int { 2 }
+ // ❌ error: actor-isolated instance method 'justThrows()' cannot be used to satisfy a protocol requirement}}
+ // cross-actor calls to 'justThrows()' are 'async throws' yet protocol requirement is only 'throws'
+
+ distributed func asyncThrows() async throws -> String { "two" } // ✅
+}
+```
+
+Let us focus on the last example, `asyncThrows()` which is declared as a throwing and asynchronous protocol requirement, and returns a `String`. We are able to witness this requirement, but we should mention the future direction of compile time serialization checking while discussing this function as well.
+
+If we recall the previously mentioned serialization conformance checking mechanism, we could imagine that the `ExampleActor` configured itself to use e.g. `Codable` for its message serialization. This means that the method declarations are subject to `Codable` checking:
+
+```swift
+distributed actor CodableExampleActor: Example {
+ typealias SerializationRequirement = Codable
+
+ distributed func asyncThrows() async throws -> String { "two" } // ✅ ok, String is Codable
+}
+```
+
+As we can see, we were still able to successfully witness the `asyncThrows` protocol requirement, since the signature matches our serialization requirement. This allows us to conform to existing protocol requirements with distributed actors, without having to invent complicated wrappers.
+
+If we used a different serialization mechanism, we may have to provide a `nonisolated` witness, that converts the types expected by the protocol, to whichever types we are able to serialize (e.g. protocol buffer messages, or anything else, including custom serialization formats). Either way, we are able to work our way through and conform to protocols if necessary.
+
+It is possible to utilize `nonisolated` functions to conform to synchronous protocol requirements, however those have limited use in practice on distributed actors since they cannot access any isolated state. In practice such functions are implementable by accessing the actor's identity or actor system it belongs to, but not much else.
+
+```swift
+protocol CustomStringConvertible {
+ var description: String { get }
+}
+
+distributed actor Example: CustomStringConvertible {
+ nonisolated var description: String {
+ "distributed actor Example: \(self.identity)"
+ }
+}
+```
+
+The above example conforms a distributed actor to the well-known `CustomStringConvertible` protocol, and we can use similar techniques to implement protocols like `Hashable`, `Identifiable`, and even `Codable`. We will discuss these in the following proposals about distributed actor runtime details though.
+
+#### The `DistributedActor` protocol and protocols inheriting from it
+
+This proposal mentioned the `DistributedActor` protocol a few times, however without going into much more depth about its design. We will leave this to the *actor runtime* focused proposals, however in regard to isolation we would like do discuss its relation to protocols and protocol conformances:
+
+The `DistributedActor` protocol cannot be conformed to explicitly by any other type other than a `distributed actor` declaration. This is similar to the `Actor` protocol and `actor` declarations.
+
+It is possible however to express protocols that inherit from the `DistributedActor` protocol, like this:
+
+```swift
+protocol Worker: DistributedActor {
+ distributed func work(on: Item) -> Int
+
+ nonisolated func same(as other: Worker) -> Bool
+
+ static func isHardWorking(_ worker: Worker) -> Bool
+}
+```
+
+Methods definitions inside distributed actor inheriting protocols must be declared either:`distributed`, `static`or `nonisolated`. Again, we value the explicitness of the definitions, and the compiler will guide and help you decide how the method shall be isolated.
+
+Note that it is always possible to conform to a distributed protocol requirement with a witness with "more" effects, since the cross-actor API remains the same - thanks to the implicit effects caused by the distributed keyword.
+
+```swift
+protocol Arnold: Worker {
+ distributed func work(on: Item) async -> Int {
+ // turns out we need this to be async internally, this is okay
+ }
+}
+```
+
+This witness works properly, because the `distributed func` requirement in the protocol is always going to be `async throws` due to the `distributed func`'s effect on the declaration. Therefore the declaration "inside the actor" can make use of `async` or `throws` without changing how the protocol can be used.
+
+### Breaking through Location Transparency
+
+Programs based on distributed actors should always be written to respect location transparency, but sometimes it is useful to break through that abstraction. The most common situation where breaking through location transparency can be useful is when writing unit tests. Such tests may need to inspect state, or call non-distributed methods, of a distributed actor instance that is known to be local.
+
+To support this kind of niche circumstance, all distributed actors offer a `whenLocal` method, which executes a provided closure based on whether it is a local instance:
+
+```swift
+extension DistributedActor {
+ /// Runs the 'body' closure if and only if the passed 'actor' is a local instance.
+ ///
+ /// Returns `nil` if the actor was remote.
+ @discardableResult
+ nonisolated func whenLocal(
+ _ body: (isolated Self) async throws -> T
+ ) async rethrows -> T?
+
+ /// Runs the 'body' closure if and only if the passed 'actor' is a local instance.
+ ///
+ /// Invokes the 'else' closure if the actor instance was remote.
+ @discardableResult
+ nonisolated func whenLocal(
+ _ body: (isolated Self) async throws -> T,
+ else whenRemote: (Self) async throws -> T
+ ) async rethrows -> T
+```
+
+When the instance is local, the `whenLocal` method exposes the distributed actor instance to the provided closure, as if it were a regular actor instance. This means you can invoke non-distributed methods when the actor instance is local, without relying on hacks that would trigger a crash if invoked on a remote instance.
+
+> **Note:** We would like to explore a slightly different shape of the `whenLocal` functions, that would allow _not_ hopping to the actor unless necessary, however we are currently lacking the implementation ability to do so. So this proposal for now shows the simple, `isolated` based approach. The alternate API we are considering would have the following shape:
+>
+> ```swift
+> @discardableResult
+> nonisolated func whenLocal(
+> _ body: (local Self) async throws -> T
+> ) reasync rethrows -> T?
+> ```
+>
+> This API could enable us to treat such `local DistActor` exactly the same as a local-only actor type; We could even consider allowing nonisolated stored properties, and allow accessing them synchronously like that:
+>
+> ```swift
+> // NOT part of this proposal, but a potential future direction
+> distributed actor FamousActor {
+> let name: String = "Emma"
+> }
+>
+> FamousActor().whenLocal { fa /*: local FamousActor*/ in
+> fa.name // OK, known to be local, distributed-isolation does not apply
+> }
+> ```
+
+## Future Directions
+
+### Versioning and Evolution of Distributed Actors and Methods
+
+Versioning and evolution of exposed `distributed` functionality is a very important, and quite vast topic to tackle. This proposal by itself does not include new capabilities - we are aware this might be limiting adoption in certain use-cases.
+
+#### Evolution of parameter values only
+
+In today's proposal, it is possible to evolve data models *inside* parameters passed through distributed method calls. This completely relies on the serialization mechanism used for the individual parameters. Most frequently, we expect Codable, or some similar mechanism, to be used here and this evolution of those values relies entirely on what the underlying encoders/decoders can do. As an example, we can define a `Message` struct like this:
+
+```swift
+struct Message: Codable {
+ let oldVersion: String
+ let onlyInNewVersion: String
+}
+
+distributed func accept(_: Message) { ... }
+```
+
+and the usual backwards / forwards evolution techniques used with `Codable` can be applied here. Most coders are able to easily ignore new unrecognized fields when decoding. It is also possible to improve or implement a different decoder that would also store unrecognized fields in some other container, e.g. like this:
+
+```swift
+struct Message: Codable {
+ let oldVersion: String
+ let unknownFields: [String: ...]
+}
+
+JSONDecoderAwareOfUnknownFields().decode(Message.self, from: ...)
+```
+
+and the decoder could populate the `unknownFields` if necessary. There are various techniques to perform schema evolution here, and we won't be explaining them in more depth here. We are aware of limitations and challenges related to `Codable` and might revisit it for improvements.
+
+#### Evolution of distributed methods
+
+The above-mentioned techniques apply only for the parameter values themselves though. With distributed methods we need to also take care of the method signatures being versioned, this is because when we declare
+
+```swift
+distributed actor Greeter {
+ distributed func greet(name: String)
+}
+```
+
+we exposed the ability to invoke `greet(name:)` to other peers. Such normal, non-generic signature will *not* cause the transmission of `String`, over the wire. They may be attempting to invoke this method, even as we roll out a new version of the "greeter server" which now has a new signature:
+
+```swift
+distributed actor Greeter {
+ distributed func greet(name: String, in language: Language)
+}
+```
+
+This is a breaking change as much in API/ABI and of course also a break in the declared wire protocol (message) that the actor is willing to accept.
+
+Today, Swift does not have great facilities to move between such definitions without manually having to keep around the forwarder methods, so we'd do the following:
+
+```swift
+distributed actor Greeter {
+
+ @available(*, deprecated, renamed: "greet(name:in:)")
+ distributed func greet(name: String) {
+ self.greet(name: name, in: .defaultLanguage)
+ }
+
+ distributed func greet(name: String, in language: Language) {
+ print("\(language.greeting), name!")
+ }
+}
+```
+
+This manual pattern is used frequently today for plain old ABI-compatible library evolution, however is fairly manual and increasingly annoying to use as more and more APIs become deprecated and parameters are added. It also means we are unable to use Swift's default argument values, and have to manually provide the default values at call-sites instead.
+
+Instead, we are interested in extending the `@available` annotation's capabilities to be able to apply to method arguments, like this:
+
+```swift
+distributed func greet(
+ name: String,
+ @available(macOS 12.1, *) in language: Language = .defaultLanguage) {
+ print("\(language.greeting), name!")
+}
+
+// compiler synthesized:
+// // "Old" API, delegating to `greet(name:in:)`
+// distributed func greet(name: String) {
+// self.greet(name: name, in: .defaultLanguage)
+// }
+```
+
+This functionality would address both ABI stable library development, and `distributed` method evolution, because effectively they share the same concern -- the need to introduce new parameters, without breaking old API. For distributed methods specifically, this would cause the emission of metadata and thunks, such that the method `greet(name:)` can be resolved from an incoming message from an "old" peer, while the actual local invocation is performed on `greet(name:in:)`.
+
+Similar to many other runtimes, removing parameters is not going to be supported, however we could look into automatically handling optional parameters, defaulting them to `nil` if not present incoming messages.
+
+In order to serve distribution well, we might have to extend what notion of "platform" is allowed in the available annotation, because these may not necessarily be specific to "OS versions" but rather "version of the distributed system cluster", which can be simply sem-ver numbers that are known to the cluster runtime:
+
+```swift
+distributed func greet(
+ name: String,
+ @available(distributed(cluster) 1.2.3, *) in language: Language = .defaultLanguage) {
+ print("\(language.greeting), name!")
+}
+```
+
+During the initial handshake peers in a distributed system exchange information about their runtime version, and this can be used to inform method lookups, or even reject "too old" clients.
+
+## Introducing the `local` keyword
+
+It would be possible to expand the way distributed actors can conform to protocols which are intended only for the actor's "local side" if we introduced a `local` keyword. It would be used to taint distributed actor variables as well as functions in protocols with a local bias.
+
+For example, `local` marked distributed actor variables could simplify the following (surprisingly common in some situations!) pattern:
+
+```swift
+distributed actor GameHost {
+ let myself: local Player
+ let others: [Player]
+
+ init(system: GameSystem) {
+ self.myself = Player(system: GameSystem)
+ self.others = []
+ }
+
+ distributed func playerJoined(_ player: Player) {
+ others.append(player)
+ if others.count >= 2 { // we need 2 other players to start a game
+ self.start()
+ }
+ }
+
+ func start() {
+ // start the game somehow, inform the local and all remote players
+ // ...
+ // Since we know `myself` is local, we can send it a closure with some logic
+ // (or other non-serializable data, like a connection etc), without having to use the whenLocal trick.
+ myself.onReceiveMessage { ... game logic here ... }
+ }
+}
+```
+
+The above example makes use of the `myself: local Player` stored property, which propagates the knowledge that the player instance stored in this property *definitely* is local, and therefore we can call non-distributed methods on it, which is useful when we need to pass it closures or other non-serializable state -- as we do in the `start()` method.
+
+An `isolated Player` where Player is a `distributed actor` would also automatically be known to be `local`, and the `whenLocal` function could be expressed more efficiently (without needing to hop to the target actor at all):
+
+```swift
+// WITHOUT `local`:
+// extension DistributedActor {
+// public nonisolated func whenLocal(_ body: @Sendable (isolated Self) async throws -> T)
+// async rethrows -> T? where T: Sendable
+
+// WITH local, we're able to not "hop" when not necessary:
+extension DistributedActor {
+ public nonisolated func whenLocal(_ body: @Sendable (local Self) async throws -> T)
+ reasync rethrows -> T? where T: Sendable // note the reasync (!)
+}
+```
+
+This version of the `whenLocal` API is more powerful, since it would allow accessing actor state without hops, if we extended the model to allow this. This would allow treating `local AnyDistributedActor` the same way as we treat any local-only actor, and can be very useful in testing.
+
+We would not have to wrap APIs in `whenLocal` or provide wrapper APIs that are `nonisolated` but actually invoke things on self, like this real problem example, from implementing a Cluster "receptionist" actor where certain calls shall only be made by the "local side", however the entire actor is accessible remotely for other peers to communicate with:
+
+```swift
+distributed actor Receptionist {
+ distributed func receiveGossip(...) { ... }
+
+ // only to be invoked by "local" actors
+ func registerLocalActor(actor: Act) where Act: DistributedActor { ... }
+}
+```
+
+Since it is too annoying to tell end-users to "always use `whenLocal` to invoke the local receptionist", library developers are forced to provide the following wrapper:
+
+```swift
+extension Receptionist {
+
+ // annoying forwarder/wrapper func; potentially unsafe, intended only for local use.
+ nonisolated func register(actor: Act) async where Act: DistributedActor {
+ await self.whenLocal { myself in
+ myself.registerLocalActor(actor: actor)
+ } else: {
+ fatalError("\(#function) must only be called on the local receptionist!")
+ }
+ }
+}
+
+// ------------------------------------
+final class System: DistributedActorSystem {
+ // ...
+ let receptionist: Receptionist
+}
+
+distributed actor Worker {
+ init(system: System) async {
+ receptionist.register(self) // ✅ OK
+ }
+}
+```
+
+This mostly works, but the implementation of the `nonisolated func register` leaves much to be desired. Rather, we want to express the following:
+
+```swift
+final class System: DistributedActorSystem {
+ // ...
+ let receptionist: local Receptionist
+}
+
+distributed actor Worker {
+ init(system: System) async {
+ await receptionist.registerLocalActor(self) // ✅ OK
+ }
+}
+```
+
+Without the need of manually implementing the "discard the distributed nature" of such actors.
+
+We see this as a natural follow up and future direction, which may take a while to implement, but would vastly improve the ergonomics of distributed actors in those special yet common enough few cases where such actors make an appearance.
+
+## Alternatives Considered
+
+This section summarizes various points in the design space for this proposal that have been considered, but ultimately rejected from this proposal.
+
+### Implicitly `distributed` methods / "opt-out of distribution"
+
+After initial feedback that `distributed func` seems to be "noisy", we actively explored the idea of alternative approaches which would reduce this perceived noise. We are convinced that implicitly distributed functions are a bad idea for the overall design, understandability, footprint and auditability of systems expressed using distributed actors.
+
+A promising idea, described by Pavel Yaskevich in the [Pitch #1](https://forums.swift.org/t/pitch-distributed-actors/51669/129) thread, was to inverse the rule, and say that _all_ functions declared on distributed actors are `distributed` by default (except `private` functions), and introduce a `local` keyword to opt-out from the distributed nature of actors. This listing exemplifies the idea:
+
+```swift
+distributed actor Worker {
+ func work(on: Item) {} // "implicitly distributed"
+ private func actualWork() {} // not distributed
+
+ local func shouldWork(on item: Item) -> Bool { ... } // NOT distributed
+}
+```
+
+However, this turns out to complicate the understanding of such a system rather than simplify it.
+
+[1] We performed an analysis of a real distributed actor runtime (that we [open sourced recently](https://swift.org/blog/distributed-actors/)), and noticed that complex distributed actors have by far more non-distributed functions, than distributed ones. It is typical for a single distributed function, to invoke multiple non distributed functions in the same actor - simply because good programming style causes the splitting out of small pieces of logic into small functions with good names; Special care would have to be taken to mark those methods local. It is easy to forget doing so, since it is not a natural concept anywhere else in Swift to have to mark things "local" -- everything else is local after all.
+
+For example, the [distributed actor cluster implementation](https://github.com/apple/swift-distributed-actors) has a few very complex actors, and their sizes are more or less as follows:
+
+- ClusterShell - a very complex actor, orchestrating node connections etc.
+ - 14 distributed methods (it's a very large and crucial actor for the actor system)
+ - ~25 local methods
+- SWIMShell, thee actor orchestrating the SWIM failure detection mechanism,
+ - 5 distributed methods
+ - 1 public local-only methods used by local callers
+ - ~12 local methods
+
+- ClusterReceptionist, responsible for discovering and gossiping information about actors
+ - 2 distributed methods
+ - 3 public local-only methods
+ - ~30 internal and private methods (lots of small helpers)
+
+- NodeDeathWatcher, responsible for monitoring node downing, and issuing associated actor termination events,
+ - 5 distributed functions
+ - no local-only methods
+
+[2] We are concerned about the auditability and review-ability of implicit distributed methods. In a plain text review it is not possible to determine whether the following introduces a distributed entry point or not. Consider the following diff, that one might be reviewing when another teammate submits a pull request:
+
+```swift
++ extension Worker {
++ func runShell(cmd: String) { // did this add a remotely invocable endpoint? we don't know from this patch!
++ // execute in shell
++ }
++ }
+```
+
+Under implicit `distributed func` rules, it is impossible to know if this function is possible to be invoked remotely. And if it were so, it could be a potential exploitation vector. Of course transports do and will implement their own authentication and authorization mechanisms, however nevertheless the inability to know if we just added a remotely invokable endpoint is worrying.
+
+In order to know if we just introduced a scary security hole in our system, we would have to go to the `Worker` definition and check if it was an `actor` or `distributed actor`.
+
+The accidental exposing can have other, unintended, side effects such as the following declaration of a method which is intended only for the actor itself to invoke it when some timer tick is triggered:
+
+```swift
+// inside some distributed actor
+func onPeriodicAckTick() { ... }
+```
+
+The method is not declared `private`, because in tests we want to be able to trigger the ticks manually. Under the implicit `distributeed func` rule, we would have to remember to make it local, as otherwise we accidentally made a function that is only intended for our own timers as remotely invocable, which could be misunderstood and/or be abused by either mistake, or malicious callers.
+
+Effectively, the implicitly-distributed rule causes more cognitive overhead to developers, every time having to mark and think about local only functions, rather than only think about the few times they actively want to _expose_ methods.
+
+[3] We initially thought we could delay additional type checks of implicit distributed functions until their first use. This would be similar to `Sendable` checking, where one can define a function accepting not-Sendable values, and only once it is attempted to be used in a cross-actor situation, we get compile errors.
+
+With distribution this poses a problem though: For example, should we allow the following conformance:
+
+```swift
+struct Item {} // NOT Codable
+
+protocol Builder {
+ func build(_: Item) async throws
+}
+
+distributed actor Bob: Builder {
+ typealias SerializationRequirement = Codable
+ func build(_: Item) async throws { ... }
+}
+```
+
+Under implicit distributed rules, we should treat this function as distributed, however that means we should be checking `Item` for the `Codable` conformance. We know at declaration time that this conformance is faulty. While in theory we could delay the error until someone actually invoked the build function:
+
+``` swift
+let bob: Bob
+try await bob.build(Item()) // ❌ error: parameter type 'Item' does not conform to 'Bob.SerializationRequirement'
+```
+
+so we have declared a method that is impossible to invoke... however if we attempted to erase `Bob` to `Builder`...
+
+```swift
+let builder: Builder = bob
+try await builder.build(Item())
+```
+
+there is nothing preventing this call from happening. There is no good way for the runtime to handle this; We would have to invent some defensive throwing modes, throwing in the distributed remote thunk, if the passed parameters do not pass what the type-system should have prevented from happening.
+
+In other words, the Sendable-like conformance model invites problematic cases which may lead to unsoundness.
+
+Thus, the only type-checking model of distributed functions, implicit or not, is an eager one. Where we fail during type checking immediately as we see the illegal declaration:
+
+```swift
+struct Item {} // NOT Codable
+
+protocol Builder {
+ func build(_: Item) async throws
+}
+
+distributed actor Bob: Builder {
+ typealias SerializationRequirement = Codable
+ func build(_: Item) async throws { ... }
+ // ❌ error: function 'build(_:)' cannot be used to satisfy protocol requirement
+ // ❌ error: parameter type 'Item' does not conform to 'Bob.SerializationRequirement'
+}
+```
+
+By itself this is fine, however this has a painful effect on common programming patterns in Swift, where we are encouraged to extract small meaningful functions that are re-used in places by the actor. We are forced to annotate _more_ APIs as `local` than we would have been with the _explicit_ `distributed` annotation model (see observation that real world distributed actors often have many small functions, not intended for distribution)
+
+[4] Since almost all functions are distributed by default in the implicit model, we need to create and store metadata for all of them, regardless if they are used or not. This may cause unnecessary binary size growth, and seems somewhat backwards to Swift's approach to be efficient and minimal in metadata produced.
+
+We are aware of runtimes where every byte counts, and would not want to prevent them from adopting distributed actors for fear of causing accidental binary size growth. In practice, we would force developers to always write `local func` unless proven that it needs to be distributed, then removing the keyword – this model feels backwards from the explicit distributed marking model, in which we make a conscious decision that "yes, this function is intended for distribution" and mark it as `distributed func` only once we actively need to.
+
+[5] While it may seem simplistic, an effective method for auditing a distributed "attack surface" of a distributed actor system is enabled by the ability search the codebase for `distributed func` and make sure all functions perform the expected authorization checks. These functions are as important as "service endpoints" and should be treated with extra care. This only works when distributed functions are explicit.
+
+We should also invest in transport-level authentication and authorization techniques, however some actions are going to be checked action-per-action, so this additional help of quickly locating distributed functions is a feature, not an annoyance.
+
+Summing up, the primary benefit of the implicit `distributed func` rule was to attempt to save developers a few keystrokes, however it fails to deliver this in practice because frequently (verified by empirical data) actors have many local methods which they do not want to expose as well. The implicit rule makes these more verbose, and results in more additional annotations. Not only that, but it causes greater mental overhead for having to remember if we're in the context of a distributed actor, and if a `func` didn't just accidentally get exposed as remotely accessible endpoint. We also noticed a few soundness and additional complexity in regard to protocol conformances that we found quite tricky.
+
+We gave this alternative design idea significant thought and strongly favor the explicit distributed rule.
+
+### Declaring actors and methods as "`distributable`"
+
+Naming of distributed actors has been debated and while it is true that `distributed` means "may be distributed (meaning 'remote') or not", this is not really the mindset we want to promote with distributed actors. The mental mindset should be that these are distributed and we must treat them this way, and they may happen to be local. Locality is the special case, distribution is the capability we're working with while designing location transparent actors. While we do envision the use of "known to be local" distributed actors, this is better solved with either a `worker.whenLocal { ...` API or allowing marking types with a `local` keyword - either approaches are not part of this proposal and will be pitched in dependently.
+
+The `distributed` keyword functions the same way as `async` on methods. Async methods are not always asynchronous. The `async` keyword merely means that such method _may suspend_. Similarly, a `distributed func` may or may not perform a remote call, as such the semantics follow the same "beware, the more expensive thing may happen" style of marking methods.
+
+### Unconditionally conforming `DistributedActor` to `Codable`
+
+This was part of an earlier design, where the distributed actor protocol was declared as:
+
+```swift
+protocol DistributedActor: AnyActor, Sendable, Codable, ... { ... }
+```
+
+forcing all implementations of distributed actors to implement the Codable `init(from:)` initializer and `encode(to:)` method.
+
+While we indeed to expect `Codable` to play a large role in some distributed actor implementations, we have specific use-cases in mind where:
+
+- Codable might not be used _at all_, thus the re-design and strong focus on being serialization mechanism agnostic in the proposal, by introducing the `SerializationRequirement` associated type.
+- Some distributed actor runtimes may behave more like "services" which are _not_ meant to be "passed around" to other nodes. This capability has been explicitly requested by some early adopters in IPC scenarios, where it will help to clean up vague and hacky solutions today, with a clear model where some distributed actors are Codable and thus "pass-around-able" and some are not, depending on the specifics how they were created.
+
+As such, we are left with no other implementation approach other than the implicit conformance, because it is not possible to add the `Codable` conformance to types managed by a distributed actor system that _wants to_ make distributed actors Codable otherwise (i.e. it is not possible to express `extension DistributedActor: Codable where ID: Codable {}` in today's Swift). Alternative approaches force implementations into casting and doing unsafe tricksy and lose out on the type-safety of only passing Codable actors to distributed methods.
+
+For distributed actor systems which _do not_ use `Codable`, forcing them to implement Codable methods and initializers would be quite a problem and the implementations would likely be implemented as just crashing. Implementations may force actors to conform to some other protocol, like `IPCServiceDistributedActor` which conforms to the `SerializationRequirement` and attempts to initialize an actor which does not conform to this protocol can crash eagerly, at initialization time. This way actor system authors gain the same developer experience as using `Codable` for passing distributed actors through distributed methods, but the initialization can be specialized -- as it is intended to, because libraries may require specific things from actor types after all.
+
+### Introducing "wrapper" type for `Distributed`
+
+We did consider (and have implemented, assisted by swift-syntax based source-generation) the idea of wrapping distributed actors using some "wrapper" type, that would delegate calls to all distributed functions, but prevent access to e.g. stored properties wrapped by such instance.
+
+This loses the benefit that a proper nominal type distributed actor offers though: the easy to incrementally move actors to distribution as it becomes necessary. The complexity of forming the "call forwarding" functions is also problematic, and extensions to such types would be confusing, would we have to do extensions like this?
+
+```swift
+extension Distributed where Actor == SomeActor {
+ func hi() { ... }
+}
+```
+
+while _also_ forwarding to functions extended on the `SomeActor` itself?
+
+```swift
+extension SomeActor {
+ func hi() { ... } // conflict?
+}
+```
+
+What would that mean for when we try to call `hi()` on a distributed actor? It also does not really simplify testing, as we want to test the actual actor, but also the distributed functions actually working correctly (i.e. enforcing serialization constraints on parameters).
+
+### Creating only a library and/or source-generation tool
+
+While this may be a highly subjective and sensitive topic, we want to tackle the question up-front, so why are distributed actors better than "just" some RPC library?
+
+The answer lies in the language integration and the mental model developers can work with when working with distributed actors. Swift already embraces actors for its local concurrency programming, and they will be omni-present and become a familiar and useful tool for developers. It is also important to notice that any async function may be technically performing work over network, and it is up to developers to manage such calls in order to not overwhelm the network etc. With distributed actors, such calls are more _visible_ because IDEs have the necessary information to e.g. underline or otherwise highlight that a function is likely to hit the network and one may need to consider its latency more, than if it was just a local call. IDEs and linters can even use this statically available information to write hints such as "hey, you're doing this distributed actor call in a tight loop - are you sure you want to do that?"
+
+Distributed actors, unlike "raw" RPC frameworks, help developers think about their distributed applications in terms of a network of collaborating actors, rather than having to think and carefully manage every single serialization call and network connection management between many connected peers - which we envision to be more and more important in the future of device and server programming et al. You may also refer to the [Swift Concurrency Manifesto; Part 4: Improving system architecture](https://gist.github.com/lattner/31ed37682ef1576b16bca1432ea9f782#part-4-improving-system-architecture) section for some other ideas on the topic.
+
+This does _not_ mean that we shun RPC style libraries or plain-old HTTP clients and libraries similar to them, which may rather be expressed as non-actor types with asynchronous functions. They still absolutely have their place, and we do not envision distributed actors fully replacing them - they are fantastic for cross-language communication, however distributed actors offer a vastly superior programming model, while we remain mostly within Swift and associated actor implementations (we *could*, communicate with non-swift actors over the network, however have not invested into this yet). We do mean however that extending the actor model to its natural habitat (networking) will enable developers to build some kinds of interactive multi-peer/multi-node systems far more naturally than each time having to re-invent a similar abstraction layer, never quite reaching the integration smoothness as language provided integration points such as distributed actors can offer.
+
+## Acknowledgments & Prior Art
+
+We would like to acknowledge the prior art in the space of distributed actor systems which have inspired our design and thinking over the years. Most notably we would like to thank the Akka and Orleans projects, each showing independent innovation in their respective ecosystems and implementation approaches. As these are library-only solutions, they have to rely on wrapper types to perform the hiding of information, and/or source generation; we achieve the same goal by expanding the already present in Swift actor-isolation checking mechanisms.
+
+We would also like to acknowledge the Erlang BEAM runtime and Elixir language for a more modern take built upon the on the same foundations, which have greatly inspired our design, however take a very different approach to actor isolation (i.e. complete isolation, including separate heaps for actors).
+
+## Source compatibility
+
+This change is purely additive to the source language.
+
+The additional use of the keyword `distributed` in `distributed actor` and `distributed func` applies more restrictive requirements to the use of such an actor, however this only applies to new code, as such no existing code is impacted.
+
+Marking an actor as distributed when it previously was not is potentially source-breaking, as it adds additional type checking requirements to the type.
+
+## Effect on ABI stability
+
+None.
+
+## Effect on API resilience
+
+None.
+
+## Changelog
+
+- 1.3.1 Minor cleanups
+ - Allow `private distributed func`
+ - Allow generic distributed actor declarations
+- 1.3 More about serialization typechecking and introducing mentioned protocols explicitly
+ - Revisions Introduce `DistributedActor` and `DistributedActorSystem` protocols properly
+ - Discuss future directions for versioning and evolving APIs
+ - Introduce conditional Codable conformance of distributed actors, based on ID
+ - Discuss `SerializationRequirement` driven typechecking of distributed methods
+ - Discuss `DistributedActorSystem` parameter requirement in required initializers
+ - Discuss isolation states in depth "isolated", "known to be local", "potentially remote" and their effect on implicit effects on call-sites
+- 1.2 Drop implicitly distributed methods
+- 1.1 Implicitly distributed methods
+- 1.0 Initial revision
+- [Pitch: Distributed Actors](https://forums.swift.org/t/pitch-distributed-actors/51669)
+ - Which focused on the general concept of distributed actors, and will from here on be cut up in smaller, reviewable pieces that will become their own independent proposals; Similar to how Swift Concurrency is a single coherent feature, however was introduced throughout many interconnected Swift Evolution proposals.
diff --git a/proposals/0337-support-incremental-migration-to-concurrency-checking.md b/proposals/0337-support-incremental-migration-to-concurrency-checking.md
new file mode 100644
index 0000000000..f3804f5a8f
--- /dev/null
+++ b/proposals/0337-support-incremental-migration-to-concurrency-checking.md
@@ -0,0 +1,286 @@
+# Incremental migration to concurrency checking
+
+* Proposal: [SE-0337](0337-support-incremental-migration-to-concurrency-checking.md)
+* Authors: [Doug Gregor](https://github.com/DougGregor), [Becca Royal-Gordon](https://github.com/beccadax)
+* Review Manager: [Ben Cohen](https://github.com/AirspeedSwift)
+* Status: **Implemented (Swift 5.6)**
+* Upcoming Feature Flag: `StrictConcurrency` (Implemented in Swift 6.0) (Enabled in Swift 6 language mode)
+* Implementation: [Pull request](https://github.com/apple/swift/pull/40680), [Linux toolchain](https://ci.swift.org/job/swift-PR-toolchain-Linux/761//artifact/branch-main/swift-PR-40680-761-ubuntu16.04.tar.gz), [macOS toolchain](https://ci.swift.org/job/swift-PR-toolchain-osx/1256//artifact/branch-main/swift-PR-40680-1256-osx.tar.gz)
+
+## Introduction
+
+Swift 5.5 introduced mechanisms to eliminate data races from the language, including the `Sendable` protocol ([SE-0302](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0302-concurrent-value-and-concurrent-closures.md)) to indicate which types have values that can safely be used across task and actor boundaries, and global actors ([SE-0316](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0316-global-actors.md)) to help ensure proper synchronization with (e.g.) the main actor. However, Swift 5.5 does not fully enforce `Sendable` nor all uses of the main actor because interacting with modules which have not been updated for Swift Concurrency was found to be too onerous. We propose adding features to help developers migrate their code to support concurrency and interoperate with other modules that have not yet adopted it, providing a smooth path for the Swift ecosystem to eliminate data races.
+
+Swift-evolution threads: [[Pitch] Staging in `Sendable` checking](https://forums.swift.org/t/pitch-staging-in-sendable-checking/51341), [Pitch #2](https://forums.swift.org/t/pitch-2-staging-in-sendable-checking/52413), [Pitch #3](https://forums.swift.org/t/pitch-3-incremental-migration-to-concurrency-checking/53610)
+
+## Motivation
+
+Swift Concurrency seeks to provide a mechanism for isolating state in concurrent programs to eliminate data races. The primary mechanism is `Sendable` checking. APIs which send data across task or actor boundaries require their inputs to conform to the `Sendable` protocol; types which are safe to send declare conformance, and the compiler checks that these types only contain `Sendable` types, unless the type's author explicitly indicates that the type is implemented so that it uses any un-`Sendable` contents safely.
+
+This would all be well and good if we were writing Swift 1, a brand-new language which did not need to interoperate with any existing code. Instead, we are writing Swift 6, a new version of an existing language with millions of lines of existing libraries and deep interoperation with C and Objective-C. None of this code specifies any of its concurrency behavior in a way that `Sendable` checking can understand, but until it can be updated, we still want to use it from Swift.
+
+There are several areas where we wish to address adoption difficulties.
+
+### Adding retroactive concurrency annotations to libraries
+
+Many existing APIs should be updated to formally specify concurrency behavior that they have always followed, but have not been able to describe to the compiler until now. For instance, it has always been the case that most UIKit methods and properties should only be used on the main thread, but before the `@MainActor` attribute, this behavior could only be documented and asserted in the implementation, not described to the compiler.
+
+Thus, many modules should undertake a comprehensive audit of their APIs to decide where to add concurrency annotations. But if they try to do so with the tools they currently have, this will surely cause source breaks. For instance, if a method is marked `@MainActor`, projects which have not yet adopted Swift Concurrency will be unable to call it even if they are using it correctly, because the project does not yet have the annotations to *prove to the compiler* that the call will run in the main actor.
+
+In some cases, these changes can even cause ABI breaks. For instance, `@Sendable` attributes on function types and `Sendable` constraints on generic parameters are incorporated into mangled function names, even though `Sendable` conformances otherwise have no impact on the calling convention (there isn't an extra witness table parameter, for instance). A mechanism is needed to enforce these constraints during typechecking, but generate code as though they do not exist.
+
+Here, we need:
+
+* A formal specification of a "compatibility mode" for pre-concurrency code which imports post-concurrency modules
+
+* A way to mark declarations as needing special treatment in this "compatibility mode" because their signatures were changed for concurrency
+
+### Adopting `Sendable` checking before the modules you use have been updated
+
+The process of auditing libraries to add concurrency annotations will take a long time. We don't think it's realistic for each module to wait until all of its libraries have been updated before they can start adopting `Sendable` checking.
+
+This means modules need a way to work around incomplete annotations in their imports--either by tweaking the specifications of imported declarations, or by telling the compiler to ignore errors. Whatever mechanism we use, we don't want it to be too verbose, though; for example, marking every single variable of a non-`Sendable` type which we want to treat as `Sendable` would be pretty painful.
+
+We must also pay special attention to what happens when the library finally *does* add its concurrency annotations, and they reveal that a client has made a mistaken assumption about its concurrency behavior. For instance, suppose you import type `Point` from module `Geometry`. You enable `Sendable` checking before `Geometry`'s maintainers have added concurrency annotations, so it diagnoses a call that sends a `Point` to a different actor. Based on the publicly-known information about `Point`, you decide that this type is probably `Sendable`, so you silence this diagnostic. However, `Geometry`'s maintainers later examine the implementation of `Point` and determine that it is *not* safe to send, so they mark it as non-`Sendable`. What should happen when you get the updated version of `Geometry` and rebuild your project?
+
+Ideally, Swift should not continue to suppress the diagnostic about this bug. After all, the `Geometry` team has now marked the type as non-`Sendable`, and that is more definitive than your guess that it would be `Sendable`. On the other hand, it probably shouldn't *prevent* you from rebuilding your project either, because this bug is not a regression. The updated `Geometry` module did not add a bug to your code; your code was already buggy. It merely *revealed* that your code was buggy. That's an improvement on the status quo--a diagnosed bug is better than a hidden one.
+
+But if Swift reacts to this bug's discovery by preventing you from building a module that built fine yesterday, you might have to put off updating the `Geometry` module or even pressure `Geometry`'s maintainers to delay their update until you can fix it, slowing forward progress. So when your module assumes something about an imported declaration that is later proven to be incorrect, Swift should emit a *warning*, not an error, about the bug, so that you know about the bug but do not have to correct it just to make your project build again.
+
+Here, we need:
+
+* A mechanism to silence diagnostics about missing concurrency annotations related to a particular declaration or module
+
+* Rules which cause those diagnostics to return once concurrency annotations have been added, but only as warnings, not errors
+
+## Proposed solution
+
+We propose a suite of features to aid in the adoption of concurrency annotations, especially `Sendable` checking. These features are designed to enable the following workflow for adopting concurrency checking:
+
+1. Enable concurrency checking, by adopting concurrency features (such as `async/await` or actors), enabling Swift 6 mode, or adding the `-warn-concurrency` flag. This causes new errors or warnings to appear when concurrency constraints are violated.
+
+2. Start solving those problems. If they relate to types from another module, a fix-it will suggest using a special kind of import, `@preconcurrency import`, which silences these warnings.
+
+3. Once you've solved these problems, integrate your changes into the larger build.
+
+4. At some future point, a module you import may be updated to add `Sendable` conformances and other concurrency annotations. If it is, and your code violates the new constraints, you will see warnings telling you about these mistakes; these are latent concurrency bugs in your code. Correct them.
+
+5. Once you've fixed those bugs, or if there aren't any, you will see a warning telling you that the `@preconcurrency import` is unnecessary. Remove the `@preconcurrency` attribute. Any `Sendable`-checking failures involving that module from that point forward will not suggest using `@preconcurrency import` and, in Swift 6 mode, will be errors that prevent your project from building.
+
+Achieving this will require several features working in tandem:
+
+* In Swift 6 mode, all code will be checked completely for missing `Sendable` conformances and other concurrency violations, with mistakes generally diagnosed as errors. The `-warn-concurrency` flag will diagnose these violations as warnings in older language versions.
+
+* When applied to a nominal declaration, the `@preconcurrency` attribute specifies that a declaration was modified to update it for concurrency checking, so the compiler should allow some uses in Swift 5 mode that violate concurrency checking, and generate code that interoperates with pre-concurrency binaries.
+
+* When applied to an `import` statement, the `@preconcurrency` attribute tells the compiler that it should only diagnose `Sendable`-requiring uses of non-`Sendable` types from that module if the type explicitly declares a `Sendable` conformance that is unavailable or has constraints that are not satisfied; even then, this will only be a warning, not an error.
+
+
+## Detailed design
+
+### Recovery behavior
+
+When this proposal speaks of an error being emitted as a warning or suppressed, it means that the compiler will recover by behaving as though (in order of preference):
+
+* A nominal type that does not conform to `Sendable` does.
+
+* A function type with an `@Sendable` or global actor attribute doesn't have it.
+
+### Concurrency checking modes
+
+Every scope in Swift can be described as having one of two "concurrency checking modes":
+
+* **Strict concurrency checking**: Missing `Sendable` conformances or global-actor annotations are diagnosed. In Swift 6, these will generally be errors; in Swift 5 mode and with nominal declarations visible via `@preconcurrency import` (defined below), these diagnostics will be warnings.
+
+* **Minimal concurrency checking**: Missing `Sendable` conformances or global-actor annotations are diagnosed as warnings; on nominal declarations, `@preconcurrency` (defined below) has special effects in this mode which suppress many diagnostics.
+
+The top level scope's concurrency checking mode is:
+
+* **Strict** when the module is being compiled in Swift 6 mode or later, when the `-warn-concurrency` flag is used with an earlier language mode, or when the file being parsed is a module interface.
+
+* **Minimal** otherwise.
+
+A child scope's concurrency checking mode is:
+
+* **Strict** if the parent's concurrency checking mode is **Minimal** and any of the following conditions is true of the child scope:
+
+ * It is a closure with an explicit global actor attribute.
+
+ * It is a closure or autoclosure whose type is `async` or `@Sendable`. (Note that the fact that the parent scope is in Minimal mode may affect whether the closure's type is inferred to be `@Sendable`.)
+
+ * It is a declaration with an explicit `nonisolated` or global actor attribute.
+
+ * It is a function, method, initializer, accessor, variable, or subscript which is marked `async` or `@Sendable`.
+
+ * It is an `actor` declaration.
+
+* Otherwise, the same as the parent scope's.
+
+> Implementation note: The logic for determining whether a child scope is in Minimal or Strict mode is currently implemented in `swift::contextRequiresStrictConcurrencyChecking()`.
+
+Imported C declarations belong to a scope with Minimal concurrency checking.
+
+### `@preconcurrency` attribute on nominal declarations
+
+To describe their concurrency behavior, maintainers must change some existing declarations in ways which, by themselves, could be source-breaking in pre-concurrency code or ABI-breaking when interoperating with previously-compiled binaries. In particular, they may need to:
+
+* Add `@Sendable` or global actor attributes to function types
+* Add `Sendable` constraints to generic signatures
+* Add global actor attributes to declarations
+
+When applied to a nominal declaration, the `@preconcurrency` attribute indicates that a declaration existed before the module it belongs to fully adopted concurrency, so the compiler should take steps to avoid these source and ABI breaks. It can be applied to any `enum`, enum `case`, `struct`, `class`, `actor`, `protocol`, `var`, `let`, `subscript`, `init` or `func` declaration.
+
+When a nominal declaration uses `@preconcurrency`:
+
+* Its name is mangled as though it does not use any of the listed features.
+
+* At use sites whose enclosing scope uses Minimal concurrency checking, the compiler will suppress any diagnostics about mismatches in these traits.
+
+* The ABI checker will remove any use of these features when it produces its digests.
+
+Objective-C declarations are always imported as though they were annotated with `@preconcurrency`.
+
+For example, consider a function that can only be called on the main actor, then runs the provided closure on a different task:
+
+```swift
+@MainActor func doSomethingThenFollowUp(_ body: @Sendable () -> Void) {
+ // do something
+ Task.detached {
+ // do something else
+ body()
+ }
+}
+```
+
+This function could have existed before concurrency, without the `@MainActor` and `@Sendable` annotations. After adding these concurrency annotations, code that worked previously would start producing errors:
+
+```swift
+class MyButton {
+ var clickedCount = 0
+
+ func onClicked() { // always called on the main thread by the system
+ doSomethingThenFollowUp { // ERROR: cannot call @MainActor function outside the main actor
+ clickedCount += 1 // ERROR: captured 'self' with non-Sendable type `MyButton` in @Sendable closure
+ }
+ }
+}
+```
+
+However, if we add `@preconcurrency` to the declaration of `doSomethingThenFollowUp`, its type is adjusted to remove both the `@MainActor` and the `@Sendable`, eliminating the errors and providing the same type inference from before concurrency was adopted by `doSomethingThenFollowUp`. The difference is visible in the type of `doSomethingThenFollowUp` in a minimal vs. a strict context:
+
+```swift
+func minimal() {
+ let fn = doSomethingThenFollowUp // type is (( )-> Void) -> Void
+}
+
+func strict() async {
+ let fn = doSomethingThenFollowUp // type is @MainActor (@Sendable ( )-> Void) -> Void
+}
+```
+
+### `Sendable` conformance status
+
+A type can be described as having one of the following three `Sendable` conformance statuses:
+
+* **Explicitly `Sendable`** if it actually conforms to `Sendable`, whether via explicit declaration or because the `Sendable` conformance was inferred based on the rules specified in [SE-0302](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0302-concurrent-value-and-concurrent-closures.md).
+
+* **Explicitly non-`Sendable`** if a `Sendable` conformance has been declared for the type, but it is not available or has constraints the type does not satisfy, *or* if the type was declared in a scope that uses Strict concurrency checking.[2]
+
+* **Implicitly non-`Sendable`** if no `Sendable` conformance has been declared on this type at all.
+
+> [2] This means that, if a module is compiled with Swift 6 mode or the `-warn-concurrency` flag, all of its types are either explicitly `Sendable` or explicitly non-`Sendable`.
+
+A type can be made explicitly non-`Sendable` by creating an unavailable conformance to `Sendable`, e.g.,
+
+```swift
+@available(*, unavailable)
+extension Point: Sendable { }
+```
+
+Such a conformance suppresses the implicit conformance of a type to `Sendable`.
+
+### `@preconcurrency` on `Sendable` protocols
+
+Some number of existing protocols describe types that should all be `Sendable`. When such protocols are updated for concurrency, they will likely inherit from the `Sendable` protocol. However, doing so will break existing types that conform to the protocol and are now assumed to be `Sendable`. This problem was [described in SE-0302](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0302-concurrent-value-and-concurrent-closures.md#thrown-errors) because it affects the `Error` and `CodingKey` protocols from the standard library:
+
+```swift
+protocol Error: /* newly added */ Sendable { ... }
+
+class MutableStorage {
+ var counter: Int
+}
+struct ProblematicError: Error {
+ var storage: MutableStorage // error: Sendable struct ProblematicError has non-Sendable stored property of type MutableStorage
+}
+```
+
+To address this, SE-0302 says the following about the additional of `Sendable` to the `Error` protocol:
+
+> To ease the transition, errors about types that get their `Sendable` conformances through `Error` will be downgraded to warnings in Swift < 6.
+
+We propose to replace this bespoke rule for `Error` and `CodingKey` to apply to every protocol that is annotated with `@preconcurrency` and inherits from `Sendable`. These two standard-library protocols will use `@preconcurrency`:
+
+```swift
+@preconcurrency protocol Error: Sendable { ... }
+@preconcurrency protocol CodingKey: Sendable { ... }
+```
+
+### `@preconcurrency` attribute on `import` declarations
+
+The `@preconcurrency` attribute can be applied to an `import` declaration to indicate that the compiler should reduce the strength of some concurrency-checking violations caused by types imported from that module. You can use it to import a module which has not yet been updated with concurrency annotations; if you do, the compiler will tell you when all of the types you need to be `Sendable` have been annotated. It also serves as a temporary escape hatch to keep your project compiling until any mistaken assumptions you had about that module are fixed.
+
+When an import is marked `@preconcurrency`, the following rules are in effect:
+
+* If an implicitly non-`Sendable` type is used where a `Sendable` type is needed:
+
+ * If the type is visible through a `@preconcurrency import`, the diagnostic is suppressed (prior to Swift 6) or emitted as a warning (in Swift 6 and later).
+
+ * Otherwise, the diagnostic is emitted normally, but a separate diagnostic is provided recommending that `@preconcurrency import` be used to work around the issue.
+
+* If an explicitly non-`Sendable` type is used where a `Sendable` type is needed:
+
+ * If the type is visible through an `@preconcurrency import`, a warning is emitted instead of an error, even in Swift 6.
+
+ * Otherwise, the diagnostic is emitted normally.
+
+* If the `@preconcurrency` attribute is unused[3], a warning will be emitted recommending that it be removed.
+
+> [3] We don't define "unused" more specifically because we aren't sure if we can refine it enough to, for instance, recommend removing one of a pair of `@preconcurrency` imports which both import an affected type.
+
+## Source compatibility
+
+This proposal is largely motivated by source compatibility concerns. Correct use of `@preconcurrency` should prevent source breaks in code built with Minimal concurrency checking, and `@preconcurrency import` temporarily weakens concurrency-checking rules to preserve source compatibility if a project adopts Full or Strict concurrency checking before its dependencies have finished adding concurrency annotations.
+
+## Effect on ABI stability
+
+By itself, `@preconcurrency` does not change the ABI of a declaration. If it is applied to declarations which have already adopted one of the features it affects, that will create an ABI break. However, if those features are added at the same time or after `@preconcurrency` is added, adding those features will *not* break ABI.
+
+`@preconcurrency`'s tactic of disabling `Sendable` conformance errors is compatible with the current ABI because `Sendable` was designed to not emit additional metadata, have a witness table that needs to be passed, or otherwise impact the calling convention or most other parts of the ABI. It only affects the name mangling.
+
+This proposal should not otherwise affect ABI.
+
+## Effect on API resilience
+
+`@preconcurrency` on nominal declarations will need to be printed into module interfaces. It is effectively a feature to allow the evolution of APIs in ways that would otherwise break resilience.
+
+`@preconcurrency` on `import` statements will not need to be printed into module interfaces; since module interfaces use the Strict concurrency checking mode, where concurrency diagnostics are warnings, they have enough "wiggle room" to tolerate the missing conformances. (As usual, compiling a module interface silences warnings by default.)
+
+## Alternatives considered
+
+### A "concurrency epoch"
+
+If the evolution of a given module is tied to a version that can be expressed in `@available`, it is likely that there will be some specific version where it retroactively adds concurrency annotations to its public APIs, and that thereafter any new APIs will be "born" with correct concurrency annotations. We could take advantage of this by allowing the module to specify a particular version when it started ensuring that new APIs were annotated and automatically applying `@preconcurrency` to APIs available before this cutoff.
+
+This would save maintainers from having to manually add `@preconcurrency` to many of the APIs they are retroactively updating. However, it would have a number of limitations:
+
+1. It would only be useful for modules used exclusively on Darwin. Non-Darwin or cross-platform modules would still need to add `@preconcurrency` manually.
+
+2. It would only be useful for modules which are version-locked with either Swift itself or a Darwin OS. Modules in the package ecosystem, for instance, would have little use for it.
+
+3. In practice, version numbers may be insufficiently granular for this task. For instance, if a new API is added at the beginning of a development cycle and it is updated for concurrency later in that cycle, you might mistakenly assume that it will automatically get `@preconcurrency` when in fact you will need to add it by hand.
+
+Since these shortcomings significantly reduce its applicability, and you only need to add `@preconcurrency` to declarations you are explicitly editing (so you are already very close to the place where you need to add it), we think a concurrency epoch is not worth the trouble.
+
+### Objective-C and `@preconcurrency`
+
+Because all Objective-C declarations are implicitly `@preconcurrency`, there is no way to force concurrency APIs to be checked in Minimal-mode code, even if they are new enough that there should be no violating uses. We think this limitation is acceptable to simplify the process of auditing large, existing Objective-C libraries.
diff --git a/proposals/0338-clarify-execution-non-actor-async.md b/proposals/0338-clarify-execution-non-actor-async.md
new file mode 100644
index 0000000000..d7d8d29aae
--- /dev/null
+++ b/proposals/0338-clarify-execution-non-actor-async.md
@@ -0,0 +1,224 @@
+# Clarify the Execution of Non-Actor-Isolated Async Functions
+
+* Proposal: [SE-0338](0338-clarify-execution-non-actor-async.md)
+* Author: [John McCall](https://github.com/rjmccall)
+* Review Manager: [Doug Gregor](https://github.com/DougGregor)
+* Status: **Implemented (Swift 5.7)** ([Decision notes](https://forums.swift.org/t/accepted-se-0338-clarify-the-execution-of-non-actor-isolated-async-functions/54929))
+
+## Introduction
+
+[SE-0306](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0306-actors.md), which introduced actors to Swift, states that `async` functions may be actor-isolated, meaning that they formally run on some actor's executor. Nothing in either SE-0306 or [SE-0296](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0296-async-await.md) (`async`/`await`) ever specifies where asynchronous functions that *aren't* actor-isolated run. This proposal clarifies that they do not run on any actor's executor, and it tightens up the rules for [sendability checking](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0302-concurrent-value-and-concurrent-closures.md) to avoid a potential data race.
+
+## Motivation
+
+It is sometimes important that programmers be able to understand which executor is formally responsible for running a particular piece of code. A function that does a large amount of computation on an actor's executor will prevent other tasks from making progress on that actor. The proper isolation of a value may also depend on only accessing it from a particular executor (see note below). Furthermore, in some situations the current executor has other semantic impacts, such as being "inherited" by tasks created with the `Task` initializer. Therefore, Swift needs to provide an intuitive and comprehensible rule for which executors are responsible for running which code.
+
+> Note: Swift will enforce the correct isolation of data by default with `Sendable` checking. However, this will not be fully enabled until code adopts a future language mode (probably Swift 6). Even under that mode, it will be possible to opt out using `@unsafe Sendable`, making safety the programmer's responsibility. And even if neither of those caveats were true, it would still be important for programmers to be able to understand the execution rules in order to understand how best to fix an isolation error.
+
+In the current implementation of Swift, `async` functions that aren't actor-isolated never intentionally change the current executor. That is, whenever execution enters such an `async` function, it will continue on whatever the current executor is, with no specific preference for any particular executor.
+
+To be slightly more precise, we can identify three principle ways that execution can enter an `async` function:
+
+- It's called by some other `async` function.
+- It calls some other `async` function which then returns, resuming the caller.
+- It needs to suspend for internal reasons (perhaps it uses `withContinuation` or calls a runtime function that suspends), and it is resumed after that suspension.
+
+In the current implementation, calls and returns from actor-isolated functions will continue running on that actor's executor. As a result, actors are effectively "sticky": once a task switches to an actor's executor, they will remain there until either the task suspends or it needs to run on a different actor. But if a task suspends within a non-actor-isolated function for a different reason than a call or return, it will generally resume on a non-actor executor.
+
+This rule perhaps makes sense from the perspective of minimizing switches between executors, but it has several unfortunate consequences. It can lead to unexpected "overhang", where an actor's executor continues to be tied up long after it was last truly needed. An actor's executor can be surprisingly inherited by tasks created during this overhang, leading to unnecessary serialization and contention for the actor. It also becomes unclear how to properly isolate data in such a function: some data accesses may be safe because of the executor the function happens to run on dynamically, but it is unlikely that this is guaranteed by the system. All told, it is a very dynamic rule which interacts poorly with how the rest of concurrency is generally understood, both by Swift programmers and statically by the Swift implementation.
+
+## Proposed solution
+
+`async` functions that are not actor-isolated should formally run on a generic executor associated with no actor. Such functions will formally switch executors exactly like an actor-isolated function would: on any entry to the function, including calls, returns from calls, and resumption from suspension, they will switch to a generic, non-actor executor. If they were previously running on some actor's executor, that executor will become free to execute other tasks.
+
+```swift
+extension MyActor {
+ func update() async {
+ // This function is actor-isolated, so formally we switch to the actor.
+ // as soon as it is called.
+
+ // Here we call a function which is not actor-isolated.
+ let update = await session.readConsistentUpdate()
+
+ // Now we resume executing the function, so formally we switch back to
+ // the actor.
+ name = update.name
+ age = update.age
+ }
+}
+
+extension MyNetworkSession {
+ func readConsistentUpdate() async -> Update {
+ // This function is not actor-isolated, so formally we switch to a
+ // generic executor when it's called. So if we happen to be called
+ // from an actor-isolated function, we will immediately switch off the
+ // actor here.
+
+ // This code runs without any special isolation.
+
+ // Keep calling readUpdate until it returns the same thing twice in a
+ // row. If that never happens in 1000 different calls, just return the
+ // last update. This code is just for explanatory purposes; please don't
+ // expect too much from it.
+ var update: Update?
+ for i in 0..<1000 {
+ // Here we make an async call.
+ let newUpdate = await readUpdateOnce()
+
+ // Formally, we will switch back to the generic executor after the
+ // call, so if we happen to have called an actor-isolated function,
+ // we will immediately switch off of the actor here.
+
+ if update == newUpdate { break }
+ update = newUpdate
+ }
+ return update!
+ }
+}
+```
+
+## Detailed design
+
+This proposal changes the semantics of non-actor-isolated `async` functions by specifying that they behave as if they were running on a generic executor not associated with any actor. Technically, the current rule was never written down, so you could say that this proposal *sets* the semantics of these functions; in practice, though, this is an observable change in behavior.
+
+As a result of this change, the formal executor of an `async` function is always known statically:
+- actor-isolated `async` functions always formally run on the actor's executor
+- non-actor-isolated `async` functions never formally run on any actor's executor
+
+This change calls for tasks to switch executors at certain points:
+- when the function is called
+- when a call made by the function returns
+- when the function returns from an internal suspension (e.g. due to a continuation)
+As usual, these switches are subject to static and dynamic optimization. These optimizations are the same as are already done with switches to actor executors.
+
+Statically, if a non-actor-isolated async function doesn't do any significant work before returning, suspending, or making an async call, it can simply remain on the current executor and allow its caller, resumer, or callee to make whatever switches it feels are advisable. This is why this proposal is careful to talk about what executor is *formally* running the task: the actual executor is permitted to be different. Typically, this difference will not be observable, but there are some exceptions. For example, if a function makes two consecutive calls to the same actor, it's possible (but not guaranteed) that the actor will not be given up between them, preventing other work from interleaving. It is outside the scope of this proposal to define what work is "significant".
+
+Dynamically, a switch will not suspend the task if the task is already on an appropriate executor. Furthermore, some executor changes can be done cheaply without fully suspending the task by giving up the current thread.
+
+### Sendability
+
+The `Sendable` rule for calls to non-actor-isolated `async` functions is currently broken. This rule is closely tied to the execution semantics of these functions because of the role of sendability checking in proving the absence of data races. The `Sendable` rule is broken even under the current semantics, but it's arguably even more broken under the proposed rule, so we really do need to fix it as part of this proposal. (There is an alternative which would make the current rule correct, but it doesn't seem advisable; see "Alternatives Considered".)
+
+It is a basic goal of Swift concurrency that programs should be free of basic data races. In order to achieve this, we must be able to prove that all uses of certain values and memory are totally ordered. All of the code that runs on a particular task is totally ordered with respect to itself. Similarly, all of the code that runs on a particular actor is totally ordered with respect to itself. So, if we can restrict a value/memory to only be used by a single task or actor, we've proven that all of its uses are totally ordered. This is the immediate goal of sendability checking: it prevents non-`Sendable` values from being shared between different concurrent contexts and thus potentially being accessed in non-totally-ordered ways.
+
+For the purposes of sendability, the concurrent context of an actor-isolated `async` function is the actor. An actor can have non-`Sendable` values in its actor-isolated storage. Actor-isolated functions can read values from that storage into their local state, and similarly they can write values from their local state into actor-isolated storage. Therefore, such functions must strictly separate their "internal" local state from the "external" local state of the task. (It would be possible to be more lenient here, but that is outside the scope of this proposal.)
+
+The current sendability rule for `async` calls is that the arguments and results of calls to actor-isolated `async` functions must be `Sendable` unless the callee is known to be isolated to the same actor as the caller. Unfortunately, no such restriction is placed on calls to non-isolated `async` functions. That is incorrect under both the current and the proposed execution semantics of such functions because the local state of such functions is not strictly isolated to the actor.
+
+As a result, the following is allowed:
+
+```swift
+actor MyActor {
+ var isolated: NonSendableValue
+
+ // Imagine that there are two different tasks calling these two
+ // functions, and the actor runs the task for `inside_one()` first.
+
+ func inside_one() async {
+ await outside(argument: isolated)
+ }
+
+ func inside_two() async {
+ isolated.operate()
+ }
+}
+
+// This is a non-actor-isolated async function.
+func outside(argument: NonSendableValue) async {
+ // Under the current execution semantics, when we resume from this
+ // sleep, we will not be on the actor's executor anymore.
+ // Under the proposed execution semantics, we will leave the actor's
+ // executor even before sleeping.
+ await Task.sleep(nanoseconds: 1_000)
+
+ // In either case, this use of the non-Sendable value can now happen
+ // concurrently with a use of it on the actor.
+ argument.operate()
+}
+```
+
+The sendability rule for `async` calls must be changed: the arguments and results of *all* `async` calls must be `Sendable` unless:
+- the caller and callee are both known to be isolated to the same actor, or
+- the caller and callee are both known to be non-actor-isolated.
+
+## Source compatibility
+
+The change to the execution semantics will not break source compatibility. However, it's possible that recompiling code under this proposal will introduce a data race if that code was previously relying on an actor-isolated value passed as an argument to a non-actor-isolation function only being accessed on the actor's executor. There should at least be a warning in this case.
+
+The change to the sendability rule may break source compatibility for code that has already adopted concurrency.
+
+In both cases, since Swift's current behavior is clearly undesirable, these seem like necessary changes. There will not be any attempt to maintain compatibility for existing code.
+
+## Effect on ABI stability
+
+The change in execution semantics does not require additional runtime support; the compiler will simply emit a different pattern of calls.
+
+The change in the sendability rule is compile-time and has no ABI impact.
+
+## Effect on API resilience
+
+This proposal does not introduce a new feature.
+
+It may become more difficult to use `async` APIs that take non-`Sendable` arguments. Such APIs are rare and usually aren't a good idea.
+
+## Alternatives considered
+
+### Full inheritance of the caller's executor
+
+One alternative to this would be for `async` functions that aren't actor-isolated to "inherit" the executors of their callers. Essentially, they would record the current executor when they are called, and they would return to that executor whenever they're resumed.
+
+There are several benefits to this approach:
+
+- It can be seen as consistent with the behavior of calls to synchronous functions, which of course "inherit" their executor because they have no ability to change it.
+
+- It significantly improves the overhang problem relative to the current execution semantics. Overhang would be bounded by the end of the call to an actor function, since upon return the caller would resume its own executor.
+
+- It is the only alternative which would make the current sendability rule for calls to `async` functions correct.
+
+However, it has three significant drawbacks:
+
+- While the overhang would be bounded, it would still cover potentially a large amount of code. Everything called by an actor-isolated async function would resume to the actor, which could include a large amount of work that really doesn't need to be actor-isolated. Actors could become heavily contended for artificial and perhaps surprising reasons.
+
+- It would make it difficult to write code that does leave the actor, since the inheritance would be implicit and recursive. There could be an attribute which avoids the inheritance, but programmers would have to explicitly remember to use it. This is the opposite of Swift's usual language design approach (e.g. with `mutating` methods); it's better to be less permissive by default so that the places which need stronger guarantees are explicit about it.
+
+- It would substantially impede optimization. Since the current executor would be semantically observable by inheritance, optimizations that remove executor switches would still have to dynamically record the correct executor that should be inherited. Since they currently do not do this, and since there is no efficient support in the runtime for doing this, this would come at a substantial runtime cost.
+
+### Initial inheritance of the caller's executor
+
+Another alternative would be to only inherit the executor of the caller for the initial period of execution, from the call to the first suspension. Later resumptions would resume to a generic, non-actor executor.
+
+This would permit the current sendability rule for arguments, but only if we enforce that the parameters are not used after a suspension in the callee. This is more flexible, but in ways that are highly likely to prove extremely brittle and limiting; a programmer relying on this flexibility is likely to come to regret it. It would also still not permit return values to be non-`Sendable`, so the rule would still need changing.
+
+The overhang problem would be further improved relative to full inheritance. The only real overhang risk would be a function that does a lot of synchronous work before returning or suspending.
+
+Sophisticated programmers might be able to use these semantics to avoid some needless switching. It is common for `async` functions to begin with an `async` call, but if Swift has trouble analyzing the code that sets up that call, then under the proposed semantics, Swift might be unable to avoid the initial switch. However, this optimization deficiency equally affects actor-isolated `async` functions, and arguably it ought to have a consistent solution.
+
+This would still significantly inhibit optimization prior to `async` calls, since the current executor would be observable when (e.g.) creating new tasks with the `Task` initializer. Other situations would be able to optimize freely.
+
+Using a sendability rule that's sensitive to both data flow and control flow seems like a non-starter; it is far too complex for its rather weak benefits. However, using such a rule is unnecessary, and these execution semantics could instead be combined with the proposed sendability rule. Non-`Sendable` values that are isolated to the actor would not be shareable with the non-actor-isolated function, and uses of non-`Sendable` values created during the initial segment would be totally ordered by virtue of being isolated to the task.
+
+Overall, while this approach has some benefits over the proposal, it seems better to go with a consistent and wholly static rule for which executor is running any particular `async` function. Allowing a certain amount of inheritance of executors is an interesting future direction.
+
+## Future directions
+
+### Explicit inheritance of executors
+
+There is still room under this proposal for `async` functions to dynamically inherit their executor from their caller. It simply needs to be opt-in rather than opt-out. This does not seem like such an urgent need that it needs to be part of this proposal.
+
+While `reasync` functions have not yet been proposed, it would probably be reasonable for them to inherit executors, since they deliberately blur the lines between synchronous and asynchronous operation.
+
+To allow the caller to use a stronger sendability rule, to avoid over-constraining static optimization of switching, and to support a more efficient ABI, this kind of inheritance should be part of the function signature of the callee.
+
+### Control over executor-switching optimization
+
+By adding potential switches in non-actor-isolated `async` functions, this proposal puts more pressure on Swift's optimizer to eliminate unnecessary switches. It may be valuable to add a way for programmers to explicitly inform the optimizer that none of the code prior to a suspension is sensitive to the current executor.
+
+### Distinguishing actor-isolated from task-isolated values
+
+As discussed above, uses of a non-`Sendable` value may be totally ordered by being restricted to either a consistent task or a consistent actor. The current sendability rules do not distinguish between these cases; instead, all non-`Sendable` values in a function are subject to uniform restrictions. This forces the creation of hard walls between actor-isolated functions and other functions on the same task. A more expressive sendability rule would distinguish these in actor-isolated `async` functions. This would significantly decrease the degree to which this proposal infringes on reasonable expressivity in such functions.
+
+The default for parameters and return values should probably be task-isolation rather than actor-isolation, so if we're going to consider this, we need to do it soon for optimal results.
+
+## Acknowledgments
+
+Many people contributed to the development of this proposal, but I'd like to especially thank Kavon Farvardin for his part in the investigation.
diff --git a/proposals/0339-module-aliasing-for-disambiguation.md b/proposals/0339-module-aliasing-for-disambiguation.md
new file mode 100644
index 0000000000..a8e1dfdcee
--- /dev/null
+++ b/proposals/0339-module-aliasing-for-disambiguation.md
@@ -0,0 +1,261 @@
+# Module Aliasing For Disambiguation
+
+* Proposal: [SE-0339](0339-module-aliasing-for-disambiguation.md)
+* Authors: [Ellie Shin](https://github.com/elsh)
+* Review Manager: [John McCall](https://github.com/rjmccall)
+* Status: **Implemented (Swift 5.7)**
+* Pitch: [Module Aliasing](https://forums.swift.org/t/pitch-module-aliasing/51737)
+* Implementation: ([toolchain](https://github.com/apple/swift/pull/40899)),
+[apple/swift-package-manager#4023](https://github.com/apple/swift-package-manager/pull/4023), others
+* Review: ([review](https://forums.swift.org/t/se-0339-module-aliasing-for-disambiguation/54730)) ([acceptance](https://forums.swift.org/t/accepted-with-modifications-se-0339-module-aliasing-for-disambiguation/55032))
+
+## Introduction
+
+Swift does not allow multiple modules in a program to share the same name, and attempts to do so will fail to build. These name collisions can happen in a reasonable program when using multiple packages developed independently from each other. This proposal introduces a way to resolve these conflicts without making major, invasive changes to a package's source by turning a module name in source into an alias, a different unique name.
+
+## Motivation
+
+As the Swift package ecosystem has grown, programmers have begun to frequently encounter module name clashes, as seen in several forum discussions including [module name 'Logging' clash in Vapor](https://forums.swift.org/t/logging-module-name-clash-in-vapor-3/25466) and [namespacing packages/modules regarding SwiftNIO](https://forums.swift.org/t/namespacing-of-packages-modules-especially-regarding-swiftnio/24726). There are two main use cases where these arise:
+
+* Two different packages include logically different modules that happen to have the same name. Often, these modules are "internal" dependencies of the package, which would be submodules if Swift supported submodules; for example, it's common to put common utilities into a `Utils` module, which will then collide if more than one package does it. Programmers often run into this problem when adding a new dependency or upgrading an existing one.
+* Two different versions of the same package need to be included in the same program. Programmers often run into this problem when trying to upgrade a dependency that another library has pinned to a specific version. Being unable to resolve this collision makes it difficult to gradually update dependencies, forcing migration to be done all at once later.
+
+In both cases, it is important to be able to resolve the conflict without making invasive changes to the conflicting packages. While submodules might be a better long-term solution for the first case, they are not currently supported by Swift. Even if submodules were supported, they might not always be correctly adopted by packages, and it would not be reasonable for package clients to have to rewrite the package to properly use them. Submodules and other namespacing features would not completely eliminate the need to "retroactively" resolve module name conflicts.
+
+## Proposed solution
+
+We believe that module aliasing provides a systematic method for addressing module name collisions. The conflicting modules can be given unique names while still allowing the source code that depends on them to compile. There's already a way to set a module name to a different name, but we need a new aliasing technique that will allow source files referencing the original module names to compile without making source changes. This will be done via new build settings which will then translate to new compiler flags described below. Together, these low-level tools will allow conflicts to be resolved by giving modules a unique name while using aliases to avoid the need to change any source code.
+
+We propose to introduce the following new settings in SwiftPM. To illustrate the flow, let's go over an example. Consider the following scenario: `App` imports the module `Game`, which imports a module `Utils` from the same package. `App` also imports another module called `Utils` from a different package. This collision might have been introduced when updating to a new version of `Game`'s package, which introduced an "internal" `Utils` module for the first time.
+
+```
+App
+ |— Module Game (from package ‘swift-game’)
+ |— Module Utils (from package ‘swift-game’)
+ |— Module Utils (from package ‘swift-draw’)
+```
+
+The modules from each package have the following code:
+
+```swift
+[Module Game] // swift-game
+
+import Utils // swift-game
+public func start(level: Utils.Level) { ... }
+```
+
+```swift
+[Module Utils] // swift-game
+
+public struct Level { ... }
+public var currentLevel: Utils.Level { ... }
+```
+
+```swift
+[Module Utils] // swift-draw
+
+public protocol Drawable { ... }
+public class Canvas: Utils.Drawable { ... }
+```
+
+Since `App` depends on these two `Utils` modules, we have a conflict, thus we need to rename one. We will introduce a new setting in SwiftPM called `moduleAliases` that will allow setting unique names for dependencies, like so:
+```swift
+ targets: [
+ .executableTarget(
+ name: "App",
+ dependencies: [
+ .product(name: "Game", package: "swift-game", moduleAliases: ["Utils": "GameUtils"]),
+ .product(name: "Utils", package: "swift-draw"),
+ ])
+ ]
+```
+
+The setting `moduleAliases` will rename `Utils` from the `swift-game` package as `GameUtils` and alias all its references in the source code to be compiled as `GameUtils`. Since renaming one of the `Utils` modules will resolve the conflict, it is not necessary to rename the other `Utils` module. The references to `Utils` in the `Game` module will be built as `GameUtils` without requiring any source changes. If `App` needs to reference both `Utils` modules in its source code, it can do so by directly including the aliased name:
+```swift
+[App]
+
+import GameUtils
+import Utils
+```
+
+Module aliasing relies on being able to change the namespace of all declarations in a module, so initially only pure Swift modules will be supported and users will be required to opt in. Support for languages that give declarations names outside of the control of Swift, such as Objective-C, C, and C++, would be limited as it will require special handling; see the **Requirements / Limitations** section for more details.
+
+
+## Detailed design
+
+### Changes to Swift Frontend
+
+Most use cases should just require setting `moduleAliases` in a package manifest. However, it may be helpful to understand how that setting changes the compiler invocations under the hood. In our example scenario, those invocations will change as follows:
+
+1. First, we need to take the `Utils` module from `swift-game` and rename it `GameUtils`. To do this, we will compile the module as if it were actually named `GameUtils`, while treating any references to `Utils` in its source files as references to `GameUtils`.
+ 1. The first part (renaming) can be achieved by passing the new module name (`GameUtils`) to `-module-name`. The new module name will also need to be used in any flags specifying output paths, such as `-o`, `-emit-module-path`, or `-emit-module-interface-path`. For example, the binary module file should be built as `GameUtils.swiftmodule` instead of `Utils.swiftmodule`.
+ 2. The second part (treating references to `Utils` in source files as `GameUtils`) can be achieved with a new compiler flag `-module-alias [name]=[new_name]`. Here, `name` is the module name that appears in source files (`Utils`), while `new_name` is the new, unique name (`GameUtils`). So in our example, we will pass `-module-alias Utils=GameUtils`.
+
+ Putting these steps together, the compiler invocation command would be `swiftc -module-name GameUtils -emit-module-path /path/to/GameUtils.swiftmodule -module-alias Utils=GameUtils ...`.
+
+ For all intents and purposes, the true name of the module is now `GameUtils`. The name `Utils` is no longer associated with it. Module aliases can be used in specific parts of the build to allow source code that still uses the name `Utils` (possibly including the module itself) to continue to compile.
+2. Next, we need to build the module `Game`. `Game` contains references to `Utils`, which we need to treat as references to `GameUtils`. We can do this by just passing `-module-alias Utils=GameUtils` without any other changes. The overall compiler invocation command to build `Game` is `swiftc -module-name Game -module-alias Utils=GameUtils ...`.
+3. We don't need any build changes when building `App` because the source code in `App` does not expect to use the `Utils` module from `swift-game` under its original name. If `App` tries to import a module named `Utils`, that will refer to the `Utils` module from `swift-draw`, which has not been renamed. If `App` does need to import the `Utils` module from `swift-game`, it must use `import GameUtils`.
+
+
+The arguments to the `-module-alias` flag will be validated against reserved names, invalid identifiers, a wrong format or ordering (`-module-alias Utils=GameUtils` is correct but `-module-alias GameUtils=Utils` is not). The flag can be repeated to allow multiple aliases, e.g. `-module-alias Utils=GameUtils -module-alias Logging=GameLogging`, and will be checked against duplicates. Diagnostics and fix-its will contain the name `Utils` in the error messages as opposed to `GameUtils` to be consistent with the names appearing to users.
+
+The validated map of aliases will be stored in the AST context and used for dependency scanning/resolution and module loading; from the above scenario, if `Game` is built with `-module-alias Utils=GameUtils` and has `import Utils` in source code, `GameUtils.swiftmodule` should be loaded instead of `Utils.swiftmodule` during import resolution.
+
+While the name `Utils` appears in source files, the actual binary name `GameUtils` will be used for name lookup, semantic analysis, symbol mangling (e.g. `$s9GameUtils5Level`), and serialization. Since the binary names will be stored during serialization, the aliasing flag will only be needed to build the conflicting modules and their immediate consuming modules; building non-immediate consuming modules will not require the flag.
+
+Direct references to the renamed modules should only be allowed in source code if multiple conflicting modules need to be imported; in such case, a direct reference in an import statement, e.g. `import GameUtils`, is allowed. Otherwise, the original name `Utils` should be used in source code instead of the binary name `GameUtils`. The module alias map will be used to track when to disallow direct references to the binary module names in source files, and an attempt to use the binary name will result in an error along with a fix-it. This restriction is useful as it can make it easier to rename the module again later if needed, e.g. from `GameUtils` to `SwiftGameUtils`.
+
+Unlike source files, the generated interface (.swiftinterface) will contain the binary module name in all its references. The binary module name will also be stored for indexing and debugging, and treated as the source of truth.
+
+### Changes to Code Assistance / Indexing
+
+The compiler arguments including the new flag `-module-alias` will be available to SourceKit and indexing. The aliases will be stored in the AST context and used to fetch the right results for code completion and other code assistance features. They will also be stored for indexing so features such as `Jump to Definition` can navigate to declarations scoped to the binary module names.
+
+Generated documentation, quick help, and other assistance features will contain the binary module names, which will be treated as the source of truth.
+
+### Changes to Swift Driver
+
+The module aliasing arguments will be used during the dependency scan for both implicit and explicit build modes; the resolved dependency graph will contain the binary module names. In case of the explicit build mode, the dependency input passed to the frontend will contain the binary module names in its json file. Similar to the frontend, validation of the aliasing arguments will be performed at the driver.
+
+### Changes to SwiftPM
+
+To make module aliasing more accessible, we will introduce new build configs which can map to the compiler flags for aliasing described above. Let’s go over how they can be adopted by SwiftPM with the above scenario (copied here).
+```
+App
+ |— Module Game (from package ‘swift-game’)
+ |— Module Utils (from package ‘swift-game’)
+ |— Module Utils (from package ‘swift-draw’)
+```
+
+Here are the manifest examples for `swift-game` and `swift-draw`.
+
+```swift
+let package = Package(
+ name: "swift-game",
+ dependencies: [],
+ products: [
+ .library(name: "Game", targets: ["Game"]),
+ .library(name: "Utils", targets: ["Utils"]),
+ ],
+ targets: [
+ .target(name: "Game", dependencies: ["Utils"]),
+ .target(name: "Utils", dependencies: [])
+ ]
+)
+```
+
+```swift
+let package = Package(
+ name: "swift-draw",
+ dependencies: [],
+ products: [
+ .library(name: "Utils", targets: ["Utils"]),
+ ],
+ targets: [
+ .target(name: "Utils", dependencies: [])
+ ]
+)
+```
+
+The `App` manifest needs to explicitly define unique names for the conflicting modules via a new parameter called `moduleAliases`.
+```swift
+let package = Package(
+ name: "App",
+ dependencies: [
+ .package(url: https://.../swift-game.git),
+ .package(url: https://.../swift-draw.git)
+ ],
+ products: [
+ .executable(name: "App", targets: ["App"])
+ ]
+ targets: [
+ .executableTarget(
+ name: "App",
+ dependencies: [
+ .product(name: "Game", package: "swift-game", moduleAliases: ["Utils": "GameUtils"]),
+ .product(name: "Utils", package: "swift-draw"),
+ ])
+ ]
+)
+```
+
+SwiftPM will perform validations when it parses `moduleAliases`; for each entry, it will check whether the given alias is a unique name, whether there is a conflict among aliases, whether the specified module is built from source (pre-compiled modules cannot be rebuilt to respect the rename), and whether the module is a pure Swift module (see **Requirements/Limitations** section for more details).
+
+It will also check if any aliases are defined in upstream packages and override them if necessary. For example, if the `swift-game` package were modified per below and defined its own alias `SwiftUtils` for module `Utils` from a dependency package, the alias defined in `App` will override it, thus the `Utils` module from `swift-utils` will be built as `GameUtils`.
+
+```swift
+let package = Package(
+ name: "swift-game",
+ dependencies: [
+ .package(url: https://.../swift-utils.git),
+ ],
+ products: [
+ .library(name: "Game", targets: ["Game"]),
+ ],
+ targets: [
+ .target(name: "Game",
+ dependencies: [
+ .product(name: "UtilsProduct",
+ package: "swift-utils",
+ moduleAliases: ["Utils": "SwiftUtils"]),
+ ])
+ ]
+)
+```
+
+Once the validation and alias overriding steps pass, dependency resolution will take place using the new module names, and the `-module-alias [name]=[new_name]` flag will be passed to the build execution.
+
+
+### Resources
+
+Tools invoked by a build system to compile resources should be modified to handle the module aliasing. The module name entry should get the renamed value and any references to aliased modules in the resources should correctly map to the corresponding binary names. The resources likely impacted by this are IB, CoreData, and anything that explicitly requires module names. We will initially only support asset catalogs and localized strings as module names are not required for those resources.
+
+### Debugging
+
+When module aliasing is used, the binary module name will be stored in mangled symbols, e.g. `$s9GameUtils5Level` instead of `$s5Utils5Level`, which will be stored in Debuginfo.
+
+For evaluating an expression, the name `Utils` can be used as it appears in source files (which were already compiled with module aliasing); however, the result of the evaluation will contain the binary module name.
+
+If a module were to be loaded directly into lldb, the binary module name should be used, i.e. `import GameUtils` instead of `import Utils`, since it does not have access to the aliasing flag.
+
+In REPL, binary module names should be used for importing or referencing; support for aliasing in that mode may be added in the future.
+
+## Requirements / Limitations
+
+To allow module aliasing, the following requirements need to be met, which come with some limitations.
+
+* Only pure Swift modules allowed for aliasing: no ObjC/C/C++/Asm due to potential symbol collision. Similarly, `@objc(name)` is discouraged.
+* Building from source only: aliasing distributed binaries is not possible due to the impact on mangling and serialization.
+* Runtime: calls to convert String to types in module, i.e direct or indirect calls to `NSClassFromString(...)`, will fail and should be avoided.
+* For resources, only asset catalogs and localized strings are allowed.
+* Higher chance of running into the following existing issues:
+ * [Retroactive conformance](https://forums.swift.org/t/retroactive-conformances-vs-swift-in-the-os/14393): this is already not a recommended practice and should be avoided.
+ * Extension member “leaks”: this is [considered a bug](https://bugs.swift.org/browse/SR-3908) which hasn’t been fixed yet. More discussions [here](https://forums.swift.org/t/pre-pitch-import-access-control-a-modest-proposal/50087).
+* Code size increase will be more implicit thus requires a caution, although module aliasing will be opt-in and a size threshold could be added to provide a warning.
+
+## Source compatibility
+This is an additive feature. Currently when there are duplicate module names, it does not compile at all. This feature requires explicitly opting in to allow and use module aliaisng via package manifests or compiler invocation commands and does not require source code changes.
+
+## Effect on ABI stability
+The feature in this proposal does not have impact on the ABI.
+
+## Effect on API resilience
+This proposal does not introduce features that would be part of a public API.
+
+## Future Directions
+
+* Currently when a module contains a type with the same name, fully qualifying a decl in the module results in an error; it treats the left most qualifier as a type instead of the module ([SR-14195](https://bugs.swift.org/browse/SR-14195), [pitch](https://forums.swift.org/t/fixing-modules-that-contain-a-type-with-the-same-name/3025), [pitch](https://forums.swift.org/t/pitch-fully-qualified-name-syntax/28482)); `XCTest` is a good example as it contains a class called `XCTest`. Trying to access a top level function `XCTAssertEqual` via `XCTest.XCTAssertEqual(...)` results in `Type 'XCTest' has no member 'XCTAssertEqual'` error. Module aliasing could mitigate this issue by renaming `XCTest` as `XCTestFramework` without requiring source changes in the `XCTest` module and allowing the function access via `XCTestFramework.XCTAssertEqual(...)` in the user code.
+
+* Introducing new import syntax such as `import Utils as GameUtils` has been discussed in forums to improve module disambiguation. The module aliasing infrastructure described in this proposal paves the way towards using such syntax that could allow more explicit (in source code) aliasing.
+
+* Visibility change to import decl access level (from public to internal) pitched [here](https://forums.swift.org/t/pre-pitch-import-access-control-a-modest-proposal/50087) could help address the extension leaks issues mentioned in **Requirements / Limitations** section.
+
+* Swift modules that have C target dependencies could, in a limited capacity, be supported by changing visibility to C symbols.
+
+* C++ interop support could potentially allow C++ modules to be aliased besides pure Swift modules.
+
+* Nested namespacing or submodules might be a better long-term solution for some of the collision issues described in **Motivation**. However, it would not completely eliminate the need to "retroactively" resolve module name conflicts. Module aliasing does not introduce any lexical or structural changes that might have an impact on potential future submodules support; it's an orthogonal feature and can be used in conjunction if needed.
+
+## Acknowledgments
+This proposal was improved with feedback and helpful suggestions along with code reviews by Becca Royal-Gordon, Alexis Laferriere, John McCall, Joe Groff, Mike Ash, Pavel Yaskevich, Adrian Prantl, Artem Chikin, Boris Buegling, Anders Bertelrud, Tom Doron, and Johannes Weiss, and others.
diff --git a/proposals/0340-swift-noasync.md b/proposals/0340-swift-noasync.md
new file mode 100644
index 0000000000..3a95229752
--- /dev/null
+++ b/proposals/0340-swift-noasync.md
@@ -0,0 +1,375 @@
+# Unavailable From Async Attribute
+
+* Proposal: [SE-0340](0340-swift-noasync.md)
+* Authors: [Evan Wilde](https://github.com/etcwilde)
+* Review manager: [Joe Groff](https://github.com/jckarter)
+* Status: **Implemented (Swift 5.7)**
+* Implementation: [noasync availability](https://github.com/apple/swift/pull/40769)
+* Discussion: [Discussion: Unavailability from asynchronous contexts](https://forums.swift.org/t/discussion-unavailability-from-asynchronous-contexts/53088)
+* Pitch: [Pitch: Unavailability from asynchronous contexts](https://forums.swift.org/t/pitch-unavailability-from-asynchronous-contexts/53877)
+* Review: [SE-0340: Unavailable from Async Attribute](https://forums.swift.org/t/se-0340-unavailable-from-async-attribute/54852)
+* Decision Notes: [Acceptance](https://forums.swift.org/t/accepted-se-0340-unavailable-from-async-attribute/55356)
+
+## Introduction
+
+The Swift concurrency model allows tasks to resume on different threads from the
+one they were suspended on. For this reason, API that relies on thread-local
+storage, locks, mutexes, and semaphores, should not be used across suspension
+points.
+
+```swift
+func badAsyncFunc(_ mutex: UnsafeMutablePointer, _ op : () async -> ()) async {
+ // ...
+ pthread_mutex_lock(mutex)
+ await op()
+ pthread_mutex_unlock(mutex) // Bad! May unlock on a different thread!
+ // ...
+}
+```
+
+The example above exhibits undefined behaviour if `badAsyncFunc` resumes on a
+different thread than the one it started on after running `op` since
+`pthread_mutex_unlock` must be called from the same thread that locked the
+mutex.
+
+We propose extending `@available` with a new `noasync` availability kind to
+indicate API that may not be used directly from asynchronous contexts.
+
+Swift evolution thread: [Pitch: Unavailability from asynchronous contexts](https://forums.swift.org/t/pitch-unavailability-from-asynchronous-contexts/53877)
+
+## Motivation
+
+The Swift concurrency model allows tasks to suspend and resume on different
+threads. While this behaviour allows higher utility of computational resources,
+there are some nasty pitfalls that can spring on an unsuspecting programmer. One
+such pitfall is the undefined behaviour from unlocking a `pthread_mutex_t` from
+a different thread than the thread that holds the lock, locking threads may
+easily cause unexpected deadlocks, and reading from and writing to thread-local
+storage across suspension points may result in unintended behaviour that is
+difficult to debug.
+
+## Proposed Solution
+
+We propose extending `@available` to accept a `noasync` availability kind.
+The `noasync` availability kind is applicable to most declarations, but is not
+allowed on destructors as those are not explicitly called and must be callable
+from anywhere.
+
+```swift
+@available(*, noasync)
+func doSomethingNefariousWithNoOtherOptions() { }
+
+@available(*, noasync, message: "use our other shnazzy API instead!")
+func doSomethingNefariousWithLocks() { }
+
+func asyncFun() async {
+ // Error: doSomethingNefariousWithNoOtherOptions is unavailable from
+ // asynchronous contexts
+ doSomethingNefariousWithNoOtherOptions()
+
+ // Error: doSomethingNefariousWithLocks is unavailable from asynchronous
+ // contexts; use our other shanzzy API instead!
+ doSomethingNefariousWithLocks()
+}
+```
+
+The `noasync` availability attribute only prevents API usage in the immediate
+asynchronous context; wrapping a call to an unavailable API in a synchronous
+context and calling the wrapper will not emit an error. This allows for cases
+where it is possible to use the API safely within an asynchronous context, but
+in specific ways. The example below demonstrates this with an example of using a
+pthread mutex to wrap a critical section. The function ensures that there cannot
+be a suspension point between obtaining and releasing the lock, and therefore is
+safe for consumption by asynchronous contexts.
+
+```swift
+func goodAsyncFunc(_ mutex: UnsafeMutablePointer, _ op : () -> ()) async {
+ // not an error, pthread_mutex_lock is wrapped in another function
+ with_pthread_mutex_lock(mutex, do: op)
+}
+
+func with_pthread_mutex_lock(
+ _ mutex: UnsafeMutablePointer,
+ do op: () throws -> R) rethrows -> R {
+ switch pthread_mutex_lock(mutex) {
+ case 0:
+ defer { pthread_mutex_unlock(mutex) }
+ return try op()
+ case EINVAL:
+ preconditionFailure("Invalid Mutex")
+ case EDEADLK:
+ fatalError("Locking would cause a deadlock")
+ case let value:
+ fatalError("Unknown pthread_mutex_lock() return value: '\(value)'")
+ }
+}
+```
+
+The above snippet is a safe wrapper for `pthread_mutex_lock` and
+`pthread_mutex_unlock`, since the lock is not held across suspension points. The
+critical section operation must be synchronous for this to hold true though.
+The following snippet uses a synchronous closure to call the unavailable
+function, circumventing the protection provided by the attribute.
+
+```swift
+@available(*, noasync)
+func pthread_mutex_lock(_ lock: UnsafeMutablePointer) {}
+
+func asyncFun(_ mutex : UnsafeMutablePointer) async {
+ // Error! pthread_mutex_lock is unavailable from async contexts
+ pthread_mutex_lock(mutex)
+
+ // Ok! pthread_mutex_lock is not called from an async context
+ _ = { unavailableFun(mutex) }()
+
+ await someAsyncOp()
+}
+```
+
+### Replacement API
+
+In some cases, it is possible to provide an alternative that is safe. The
+`with_pthread_mutex_lock` is an example of a way to provide a safe way to wrap
+locking and unlocking pthread mutexes.
+
+In other cases, it may be safe to use an API from a specific actor. For
+example, API that uses thread-local storage isn't safe for consumption by
+asynchronous functions in general, but is safe for functions on the MainActor
+since it will only use the main thread.
+
+The unavailable API should still be annotated as such, but an alternative
+function can be implemented as an extension of the actors that support the
+operation.
+
+```swift
+@available(*, noasync, renamed: "mainactorReadID()", message: "use mainactorReadID instead")
+func readIDFromThreadLocal() -> Int { }
+
+@MainActor
+func readIDFromMainActor() -> Int { readIDFromThreadLocal() }
+
+func asyncFunc() async {
+ // Bad, we don't know what thread we're on
+ let id = readIDFromThreadLocal()
+
+ // Good, we know it's coming from the main actor on the main thread.
+ // Note the suspension due to the jump to the main actor.
+ let id = await readIDFromMainActor()
+}
+```
+
+Restricting a synchronous API to an actor is done similarly, as demonstrated in
+the example below. The synchronous `save` function is part of a public API, so
+it can't just be pulled into the `DataStore` actor without causing a source
+break. Instead, it is annotated with a `noasync` available attribute.
+`DataStore.save` is a thin wrapper around the original synchronous save
+function. Calls from an asynchronous context to `save` may only be done through
+the `DataStore` actor, ensuring that the cooperative pool isn't tied up with the
+save function. The original save function is still available to synchronous code
+as it was before.
+
+```swift
+@available(*, noasync, renamed: "DataStore.save()")
+public func save(_ line: String) { }
+
+public actor DataStore { }
+
+public extension DataStore {
+ func save(_ line: String) {
+ save(line)
+ }
+}
+```
+
+## Additional design details
+
+Verifying that unavailable functions are not used from asynchronous contexts is
+done weakly; only unavailable functions called directly from asynchronous
+contexts are diagnosed. This avoids the need to recursively typecheck the bodies
+of synchronous functions to determine whether they are implicitly available from
+asynchronous contexts, or to verify that they are appropriately annotated.
+
+While the typechecker doesn't need to emit diagnostics from synchronous
+functions, they cannot be omitted entirely. It is possible to declare
+asynchronous contexts inside of synchronous contexts, wherein diagnostics should
+be emitted.
+
+```swift
+@available(*, noasync)
+func bad2TheBone() {}
+
+func makeABadAsyncClosure() -> () async -> Void {
+ return { () async -> Void in
+ bad2TheBone() // Error: Unavailable from asynchronous contexts
+ }
+}
+```
+
+## Source Compatibility
+
+Swift 3 and Swift 4 do not have this attribute, so code coming from Swift 3 and
+Swift 4 won't be affected.
+
+The attribute will affect any current asynchronous code that currently contains
+use of API that are modified with this attribute later. To ease the transition,
+we propose that this attribute emits a warning in Swift 5.6, and becomes a full
+error in Swift 6. In cases where someone really wants unsafe behavior and enjoys
+living on the edge, the diagnostic is easily circumventable by wrapping the API
+in a synchronous closure, noted above.
+
+## Effect on ABI stability
+
+This feature has no effect on ABI.
+
+## Effect on API resilience
+
+The presence of the attribute has no effect on the ABI.
+
+## Alternatives Considered
+
+### Propagation
+
+The initial discussion focused on how unavailability propagated, including the
+following three designs;
+ - implicitly-inherited unavailability
+ - explicit unavailability
+ - thin unavailability
+
+The ultimate decision is to go with the thin checking; both the implicit and
+explicit checking have high performance costs and require far more consideration
+as they are adding another color to functions.
+
+The attribute is expected to be used for a fairly limited set of specialized
+use-cases. The goal is to provide some protection without dramatically impacting
+the performance of the compiler.
+
+#### Implicitly inherited unavailability
+
+Implicitly inheriting unavailability would transitively apply the unavailability
+to functions that called an unavailable function. This would have the lowest
+developer overhead while ensuring that one could not accidentally use the
+unavailable functions indirectly.
+
+```swift
+@unavailableFromAsync
+func blarp1() {}
+
+func blarp2() {
+ // implicitly makes blarp2 unavailable
+ blarp1()
+}
+
+func asyncFun() async {
+ // Error: blarp2 is impicitly unavailable from async because of call to blarp1
+ blarp2()
+}
+```
+
+Unfortunately, computing this is very expensive, requiring type-checking the
+bodies of every function a given function calls in order to determine if the
+declaration is available from an async context. Requiring even partial
+type-checking of the function bodies to determine the function declaration is
+prohibitively expensive, and is especially detrimental to the performance of
+incremental compilation.
+
+We would need an additional attribute to disable the checking for certain
+functions that are known to be usable from an async context, even though they
+use contain unavailable functions. An example of a safe, but "unavailable"
+function is `with_pthread_mutex_lock` above.
+
+#### Explicit unavailability
+
+This design behaves much like availability does today. In order to use an
+unavailable function, the calling function must be explicitly annotated with the
+unavailability attribute or an error is emitted.
+
+Like the implicit unavailability propagation, we still need an additional
+attribute to indicate that, while a function may contain unsafe API, it uses
+them in a way that is safe for use in asynchronous contexts.
+
+The benefits of this design are that it both ensures that unsafe API are explicitly
+handled correctly, avoiding bugs. Additionally, typechecking asynchronous
+functions is reasonably performant and does not require recursively
+type-checking the bodies of every synchronous function called by the
+asynchronous function.
+
+Unfortunately, we would need to walk the bodies of every synchronous function to
+ensure that every synchronous function is correctly annotated. This reverses the
+benefits of the implicit availability checking, while having a high developer
+overhead.
+
+### Separate Attribute
+
+We considered using a separate attribute, spelled `@unavailableFromAsync`, to
+annotate the unavailable API. After more consideration, it became apparent that
+we would likely need to reimplement much of the functionality of the
+`@available` attribute.
+
+Some thoughts that prompted the move from `@unavailableFromAsync` to an
+availability kind include:
+
+ - A given API may have different implementations on different platforms, and
+ therefore may be implemented in a way that is safe for consumption in
+ asynchronous contexts in some cases but not others.
+ - An API may be currently implemented in a way that is unsafe for consumption
+ in asynchronous contexts, but may be safe in the future.
+ - We get `message`, `renamed`, and company, with serializations, for free by
+ merging this with `@available`.
+
+Challenges to the merge mostly focus on the difference in the verification model
+between this and the other availability modes. The `noasync`, as discussed
+above, is a weaker check and does not require API that is using the unavailable
+function to also be annotated. The other availability checks do require that the
+availability information be propagated.
+
+## Future Directions
+
+[Custom executors](https://forums.swift.org/t/support-custom-executors-in-swift-concurrency/44425)
+are pitched to become part of the language as a future feature.
+Restricting an API to a custom executor is the same as restricting that API to
+an actor. The difference is that the actor providing the replacement API has
+it's `unownedExecutor` overridden with the desired custom executor.
+
+Hand-waving around some of the syntax, this protection could look something like
+the following example:
+
+```swift
+protocol IOActor : Actor { }
+
+extension IOActor {
+ nonisolated var unownedExecutor: UnownedSerialExecutor {
+ return getMyCustomIOExecutor()
+ }
+}
+
+@available(*, noasync, renamed: "IOActor.readInt()")
+func readIntFromIO() -> String { }
+
+extension IOActor {
+ // IOActor replacement API goes here
+ func readInt() -> String { readIntFromIO() }
+}
+
+actor MyIOActor : IOActor {
+ func printInt() {
+ // Okay! It's synchronous on the IOActor
+ print(readInt())
+ }
+}
+
+func print(myActor : MyIOActor) async {
+ // Okay! We only call `readIntFromIO` on the IOActor's executor
+ print(await myActor.readInt())
+}
+```
+
+The `IOActor` overrides it's `unownedExecutor` with a specific custom IO
+executor and provides a synchronous `readInt` function wrapping a call to the
+`readIntFromIO` function. The `noasync` availability attribute ensures that
+`readIntFromIO` cannot generally be used from asynchronous contexts.
+When `readInt` is called, there will be a hop to the `MyIOActor`, which uses the
+custom IO executor.
+
+## Acknowledgments
+
+Thank you Becca and Doug for you feedback and help shaping the proposal.
diff --git a/proposals/0341-opaque-parameters.md b/proposals/0341-opaque-parameters.md
new file mode 100644
index 0000000000..e324461490
--- /dev/null
+++ b/proposals/0341-opaque-parameters.md
@@ -0,0 +1,270 @@
+# Opaque Parameter Declarations
+
+* Proposal: [SE-0341](0341-opaque-parameters.md)
+* Author: [Doug Gregor](https://github.com/DougGregor)
+* Review Manager: [Ben Cohen](https://github.com/AirspeedSwift)
+* Status: **Implemented (Swift 5.7)**
+* Implementation: [apple/swift#40993](https://github.com/apple/swift/pull/40993)
+
+## Introduction
+
+Swift's syntax for generics is designed for generality, allowing one to express complicated sets of constraints amongst the different inputs and outputs of a function. For example, consider an eager concatenation operation that builds an array from two sequences:
+
+```swift
+func eagerConcatenate(
+ _ sequence1: Sequence1, _ sequence2: Sequence2
+) -> [Sequence1.Element] where Sequence1.Element == Sequence2.Element
+```
+
+There is a lot going on in that function declaration: the two function parameters are of different types determined by the caller, which are captured by `Sequence1` and `Sequence2`, respectively. Both of these types must conform to the `Sequence` protocol and, moreover, the element types of the two sequences must be equivalent. Finally, the result of this operation is an array of the sequence's element type. One can use this operation with many different inputs, so long as the constraints are met:
+
+```swift
+eagerConcatenate([1, 2, 3], Set([4, 5, 6])) // okay, produces an [Int]
+eagerConcatenate([1: "Hello", 2: "World"], [(3, "Swift"), (4, "!")]) // okay, produces an [(Int, String)]
+eagerConcatenate([1, 2, 3], ["Hello", "World"]) // error: sequence element types do not match
+```
+
+However, when one does not need to introduce a complex set of constraints, the syntax starts to feel quite heavyweight. For example, consider a function that composes two SwiftUI views horizontally:
+
+```swift
+func horizontal(_ v1: V1, _ v2: V2) -> some View {
+ HStack {
+ v1
+ v2
+ }
+}
+```
+
+There is a lot of boilerplate to declare the generic parameters `V1` and `V2` that are only used once, making this function look far more complex than it really is. The result, on the other hand, is able to use an [opaque result type](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0244-opaque-result-types.md) to hide the specific returned type (which would be complicated to describe), describing it only by the protocols to which it conforms.
+
+This proposal extends the syntax of opaque result types to parameters, allowing one to specify function parameters that are generic without the boilerplate associated with generic parameter lists. The `horizontal` function above can then be expressed as:
+
+```swift
+func horizontal(_ v1: some View, _ v2: some View) -> some View {
+ HStack {
+ v1
+ v2
+ }
+}
+```
+
+Semantically, this formulation is identical to the prior one, but is simpler to read and understand because the inessential complexity from the generic parameter lists has been removed. It takes two views (the concrete type does not matter) and returns a view (the concrete type does not matter).
+
+Swift-evolution threads: [Pitch for this proposal](https://forums.swift.org/t/pitch-opaque-parameter-types/54914), [Easing the learning curve for introducing generic parameters](https://forums.swift.org/t/discussion-easing-the-learning-curve-for-introducing-generic-parameters/52891), [Improving UI of generics pitch](https://forums.swift.org/t/improving-the-ui-of-generics/22814)
+
+## Proposed solution
+
+This proposal extends the use of the `some` keyword to parameter types for function, initializer, and subscript declarations. As with opaque result types, `some P` indicates a type that is unnamed and is only known by its constraint: it conforms to the protocol `P`. When an opaque type occurs within a parameter type, it is replaced by an (unnamed) generic parameter. For example, the given function:
+
+```swift
+func f(_ p: some P) { }
+```
+
+is equivalent to a generic function described as follows, with a synthesized (unnamable) type parameter `_T`:
+
+```swift
+func f<_T: P>(_ p: _T)
+```
+
+Note that, unlike with opaque result types, the caller determines the type of the opaque type via type inference. For example, if we assume that both `Int` and `String` conform to `P`, one can call or reference the function with either `Int` or `String`:
+
+```swift
+f(17) // okay, opaque type inferred to Int
+f("Hello") // okay, opaque type inferred to String
+
+let fInt: (Int) -> Void = f // okay, opaque type inferred to Int
+let fString: (String) -> Void = f // okay, opaque type inferred to String
+let fAmbiguous = f // error: cannot infer parameter for `some P` parameter
+```
+
+[SE-0328](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0328-structural-opaque-result-types.md) extended opaque result types to allow multiple uses of `some P` types within the result type, in any structural position. Opaque types in parameters permit the same structural uses, e.g.,
+
+```swift
+func encodeAnyDictionaryOfPairs(_ dict: [some Hashable & Codable: Pair]) -> Data
+```
+
+This is equivalent to:
+
+```swift
+func encodeAnyDictionaryOfPairs<_T1: Hashable & Codable, _T2: Codable, _T3: Codable>(_ dict: [_T1: Pair<_T2, _T3>]) -> Data
+```
+
+Each instance of `some` within the declaration represents a different implicit generic parameter.
+
+## Detailed design
+
+Opaque parameter types can only be used in parameters of a function, initializer, or subscript declaration. They cannot be used in (e.g.) a typealias or any value of function type. For example:
+
+```swift
+typealias Fn = (some P) -> Void // error: cannot use opaque types in a typealias
+let g: (some P) -> Void = f // error: cannot use opaque types in a value of function type
+```
+
+There are additional restrictions on the use of opaque types in parameters where they may conflict with future language features.
+
+### Variadic generics
+
+An opaque type cannot be used in a variadic parameter:
+
+```swift
+func acceptLots(_: some P...)
+```
+
+This restriction is in place because the semantics implied by this proposal might not be the appropriate semantics if Swift gains variadic generics. Specifically, the semantics implied by this proposal itself (without variadic generics) would be equivalent to:
+
+```swift
+func acceptLots<_T: P>(_: _T...)
+```
+
+where `acceptLots` requires that all of the arguments have the same type:
+
+```swift
+acceptLots(1, 1, 2, 3, 5, 8) // okay
+acceptLots("Hello", "Swift", "World") // okay
+acceptLots("Swift", 6) // error: argument for `some P` could be either String or Int
+```
+
+With variadic generics, one might instead make the implicit generic parameter a generic parameter pack, as follows:
+
+```swift
+func acceptLots<_Ts: P...>(_: _Ts...)
+```
+
+In this case, `acceptLots` accepts any number of arguments, all of which might have different types:
+
+```swift
+acceptLots(1, 1, 2, 3, 5, 8) // okay, Ts contains six Int types
+acceptLots("Hello", "Swift", "World") // okay, Ts contains three String types
+acceptLots(Swift, 6) // okay, Ts contains String and Int
+```
+
+### Opaque parameters in "consuming" positions of function types
+
+The resolution of [SE-0328](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0328-structural-opaque-result-types.md) prohibited the use of opaque parameters in "consuming" positions of function types. For example:
+
+```swift
+func f() -> (some P) -> Void { ... } // error: cannot use opaque type in parameter of function type
+```
+
+The result of function `f` is fairly hard to use, because there is no way for the caller to easily create a value of an unknown, unnamed type:
+
+```swift
+let fn = f()
+fn(/* how do I create a value here? */)
+```
+
+The same prohibition applies to opaque types that occur within parameters of function type, e.g.,
+
+```swift
+func g(fn: (some P) -> Void) { ... } // error: cannot use opaque type in parameter of function type
+```
+
+The reasoning for this prohibition is similar. In the implementation of `g`, it's hard to produce a value of the type `some P` when that type isn't named anywhere else.
+
+## Source compatibility
+
+This is a pure language extension with no backward-compatibility concerns, because all uses of `some` in parameter position are currently errors.
+
+## Effect on ABI stability
+
+This proposal has no effect on the ABI or runtime because it is syntactic sugar for generic parameters.
+
+## Effect on API resilience
+
+This feature is purely syntactic sugar, and one can switch between using opaque parameter types and the equivalent formulation with explicit generic parameters without breaking either the ABI or API. However, the complete set of constraints must be the same in such cases.
+
+## Future Directions
+
+### Constraining the associated types of a protocol
+
+This proposal composes well with an idea that allows the use of generic syntax to specify the associated type of a protocol, e.g., where `Collection`is "a `Collection` whose `Element` type is `String`". Combined with this proposal, one can more easily express a function that takes an arbitrary collection of strings:
+
+```swift
+func takeStrings(_: some Collection) { ... }
+```
+
+Recall the complicated `eagerConcatenate` example from the introduction:
+
+```swift
+func eagerConcatenate(
+ _ sequence1: Sequence1, _ sequence2: Sequence2
+) -> [Sequence1.Element] where Sequence1.Element == Sequence2.Element
+```
+
+With opaque parameter types and generic syntax on protocol types, one can express this in a simpler form with a single generic parameter representing the element type:
+
+```swift
+func eagerConcatenate(
+ _ sequence1: some Sequence, _ sequence2: some Sequence
+) -> [T]
+```
+
+And in conjunction with opaque result types, we can hide the representation of the result, e.g.,
+
+```swift
+func lazyConcatenate(
+ _ sequence1: some Sequence, _ sequence2: some Sequence
+) -> some Sequence
+```
+
+### Enabling opaque types in consuming positions
+
+The prohibition on opaque types in "consuming" positions could be lifted for opaque types both in parameters and in return types, but they wouldn't be useful with their current semantics because in both cases the wrong code (caller vs. callee) gets to choose the parameter. We could enable opaque types in consuming positions by "flipping" who gets to choose the parameter. To understand this, think of opaque result types as a form of "reverse generics", where there is a generic parameter list after a function's `->` and for which the function itself (the callee) gets to choose the type. For example:
+
+```swift
+func f1() -> some P { ... }
+// translates to "reverse generics" version...
+func f1() -> T { /* callee implementation here picks concrete type for T */ }
+```
+
+The problem with opaque types in consuming positions of the return type is that the callee picks the concrete type, and the caller can't reason about it. We can see this issue by translating to the reverse-generics formulation:
+
+```swift
+func f2() -> (some P) -> Void { ... }
+// translates to "reverse generics" version...
+func f2() -> (T) -> Void { /* callee implementation here picks concrete type for T */}
+```
+
+We could "flip" the caller/callee choice here by translating opaque types in consuming positions to the other side of the `->`. For example, `f2` would be translated into
+
+```swift
+// if we "flip" opaque types in consuming positions
+func f2() -> (some P) -> Void { ... }
+// translates to
+func f2() -> (T) -> Void { ... }
+```
+
+This is a more useful translation, because the caller picks the type for `T` using type context, and the callee provides a closure that can work with whatever type the caller picks, generically. For example:
+
+```swift
+let fn1: (Int) -> Void == f2 // okay, T == Int
+let fn2: (String) -> Void = f2 // okay, T == String
+```
+
+Similar logic applies to opaque types in consuming positions within parameters. Consider this function:
+
+```swift
+func g2(fn: (some P) -> Void) { ... }
+```
+
+If this translates to "normal" generics, i.e., then the parameter isn't readily usable:
+
+```swift
+// if we translated to "normal" generics
+func g2(fn: (T) -> Void) { /* how do we come up with a T to call fn with? */}
+```
+
+Again, the problem here is that the caller gets to choose what `T` is, but then the callee cannot use it effectively. We could again "flip" the generics, moving the implicit type parameter for an opaque type in consuming position to the other side of the function's `->`:
+
+```swift
+// if we "flip" opaque types in consuming positions
+func g2(fn: (some P) -> Void) { ... }
+// translates to
+func g2(fn: (T) -> Void) -> Void { ... }
+```
+
+Now, the implementation of `g2` (the callee) gets to choose the type of `T`, which is appropriate because it will be providing values of type `T` to `fn`. The caller will need to provide a closure or generic function that's able to accept any `T` that conforms to `P`. It cannot write the type out, but it can certainly make use of it via type inference, e.g.:
+
+```swift
+g2 { x in x.doSomethingSpecifiedInP() }
+```
diff --git a/proposals/0342-static-link-runtime-libraries-by-default-on-supported-platforms.md b/proposals/0342-static-link-runtime-libraries-by-default-on-supported-platforms.md
new file mode 100644
index 0000000000..788c935013
--- /dev/null
+++ b/proposals/0342-static-link-runtime-libraries-by-default-on-supported-platforms.md
@@ -0,0 +1,232 @@
+# Statically link Swift runtime libraries by default on supported platforms
+
+* Proposal: [SE-0342](0342-static-link-runtime-libraries-by-default-on-supported-platforms.md)
+* Authors: [neonichu](https://github.com/neonichu) [tomerd](https://github.com/tomerd)
+* Review Manager: [Ted Kremenek](https://github.com/tkremenek)
+* Status: **Accepted**
+* Decision Notes: [Rationale](https://forums.swift.org/t/accepted-se-0342-statically-link-swift-runtime-libraries-by-default-on-supported-platforms/56517)
+* Implementation: [apple/swift-package-manager#3905](https://github.com/apple/swift-package-manager/pull/3905)
+* Initial discussion: [Forum Thread](https://forums.swift.org/t/pre-pitch-statically-linking-the-swift-runtime-libraries-by-default-on-linux)
+* Pitch: [Forum Thread](https://forums.swift.org/t/pitch-package-manager-statically-link-swift-runtime-libraries-by-default-on-supported-platforms)
+
+## Introduction
+
+Swift 5.3.1 introduced [statically linking the Swift runtime libraries on Linux](https://forums.swift.org/t/static-linking-on-linux-in-swift-5-3-1/).
+With this feature, users can set the `--static-swift-stdlib` flag when invoking SwiftPM commands (or the long form `-Xswiftc -static-stdlib`) in order to statically link the Swift runtime libraries into the program.
+
+On some platforms, such as Linux, this is often the preferred way to link programs, since the program is easier to deploy to the target server or otherwise share.
+
+This proposal explores making it SwiftPM's default behavior when building executable programs on such platforms.
+
+## Motivation
+
+Darwin based platform ship with the Swift runtime libraries in the _dyld shared cache_.
+This allows building smaller Swift programs by dynamically linking the Swift runtime libraries.
+The shared cache keeps the cost of loading these libraries low.
+
+Other platforms, such as conventional Linux distributions, do not ship with the Swift runtime libraries.
+Hence, a deployment of a program built with Swift (e.g. a web-service or CLI tool) on such platform requires one of three options:
+
+1. Package the application with a "bag of shared objects" (the `libswift*.so` files making up Swift's runtime libraries) alongside the program.
+2. Statically link the runtime libraries using the `--static-swift-stdlib` flag described above.
+3. Use a "runtime" docker image that contain the _correct version_ of the the runtime libraries (matching the compiler version exactly).
+
+Out of the three options, the most convenient is #2 given that #1 requires manual intervention and/or additional wrapper scripts that use `ldd`, `readelf` or similar tools to deduce the correct list of runtime libraries.
+#3 is convenient but version sensitive.
+#2 also has cold start performance advantage because there is less dynamic library loading.
+However #2 comes at a cost of bigger binaries.
+
+Stepping outside the Swift ecosystem, deployment of statically linked programs is often the preferred way on server centric platforms such as Linux, as it dramatically simplifies deployment of server workloads.
+For reference, Go and Rust both chose to statically link programs by default for this reason.
+
+### Policy for system shipping with the Swift runtime libraries
+
+At this time, Darwin based systems are the only ones that ship with the Swift runtime libraries.
+In the future, other operating systems may choose to ship with the Swift runtime libraries.
+As pointed out by [John_McCall](https://forums.swift.org/u/John_McCall), in such cases the operating system vendors are likely to choose a default that is optimized for their software distribution model.
+For example, they may choose to distribute a Swift toolchain defaulting to dynamic linking (against the version of the Swift runtime libraries shipped with that system) to optimize binary size and memory consumption on that system.
+To support this, the Swift toolchain build script could include a preset to controls the default linking strategy.
+
+As pointed out by [Joe_Groff](https://forums.swift.org/u/Joe_Groff), even in such cases there is still an argument for defaulting Swift.org distributed Swift toolchains to static linking for distribution, since we want to preserve the freedom to pursue ABI-breaking improvements in top-of-tree for platforms that aren't ABI-constrained. This situation wouldn't be different from other ecosystems: The Python or Ruby that comes with macOS are set up to provide a stable runtime environment compatible with the versions of various Python- and Ruby-based tools and libraries packaged by the distribution, but developers can and do often install their own local Python/Ruby interpreter if they need a language version different from the vendor's, or a package that's incompatible with the vendor's interpreter.
+
+## Proposed solution
+
+Given that at this time Darwin based systems are the only ones that ship with the Swift runtime libraries,
+we propose to make statically linking of the Swift runtime libraries SwiftPM's default behavior when building executables in release mode on non-Darwin platforms that support such linking,
+with an opt-out way to disable this default behavior.
+
+Building in debug mode will continue to dynamically link the Swift runtime libraries, given that debugging requires the Swift toolchain to be installed and as such the Swift runtime libraries are by definition present.
+
+Note that SwiftPM's default behavior could change over time as its designed to reflect the state and available options of Swift runtime distribution on that platform. In other words, whether or not a SwiftPM defaults to static linking of the Swift runtime libraries is a by-product of the state of Swift runtime distribution on a platform.
+
+Also note this does not mean the resulting program is fully statically linked - only the Swift runtime libraries (stdlib, Foundation, Dispatch, etc) would be statically linked into the program, while external dependencies will continue to be dynamically linked and would remain a concern left to the user when deploying Swift based programs.
+Such external dependencies include:
+1. Glibc (including `libc.so`, `libm.so`, `libdl.so`, `libutil.so`): On Linux, Swift relies on Glibc to interact with the system and its not possible to fully statically link programs based on Glibc. In practice this is usually not a problem since most/all Linux systems ship with a compatible Glibc.
+2. `libstdc++` and `libgcc_s.so`: Swift on Linux also relies on GNU's C++ standard library as well as GCC's runtime library which much like Glibc is usually not a problem because a compatible version is often already installed on the target system.
+3. At this time, non-Darwin version of Foundation (aka libCoreFoundation) has two modules that rely on system dependencies (`FoundationXML` on `libxml2` and `FoundationNetworking` on `libcurl`) which cannot be statically linked at this time and require to be installed on the target system.
+4. Any system dependencies the program itself brings (e.g. `libsqlite`, `zlib`) would not be statically linked and must be installed on the target system.
+
+
+## Detailed design
+
+The changes proposed are focused on the behavior of SwiftPM.
+We propose to change SwiftPM's default linking of the Swift runtime libraries when building executables as follows:
+
+### Default behavior
+
+* Darwin-based platforms used to support statically linking the Swift runtime libraries in the past (and never supported fully static binaries).
+ Today however, the Swift runtime library is shipped with the operating system and can therefore not easily be included statically in the binary.
+ Naturally, dynamically linking the Swift runtime libraries will remain the default on Darwin.
+
+* Linux and WASI support static linking and would benefit from it for the reasons highlighted above.
+ We propose to change the default on these platforms to statically link the Swift runtime libraries.
+
+* Windows may benefit from statically linking for the reasons highlighted above but it is not technically supported at this time.
+ As such the default on Windows will remain dynamically linking the Swift runtime libraries.
+
+* The default behavior on platforms not listed above will remain dynamically linking the Swift runtime libraries.
+
+### Opt-in vs. Opt-out
+
+SwiftPM's `--static-swift-stdlib` CLI flag is designed as an opt-in way to achieve static linking of the Swift runtime libraries.
+
+We propose to deprecate `--static-swift-stdlib` and introduce a new flag `--disable-static-swift-runtime` which is designed as an opt-out from the default behavior described above.
+
+Users that want to force static linking (as with `--static-swift-stdlib`) can use the long form `-Xswiftc -static-stdlib`.
+
+### Example
+
+Consider the following simple program:
+
+```bash
+$ swift package init --type executable
+Creating executable package: test
+Creating Package.swift
+Creating README.md
+Creating .gitignore
+Creating Sources/
+Creating Sources/test/main.swift
+Creating Tests/
+Creating Tests/testTests/
+Creating Tests/testTests/testTests.swift
+
+$ cat Sources/test/main.swift
+print("Hello, world!")
+```
+Building the program with default dynamic linking yields the following:
+
+```bash
+$ swift build -c release
+[3/3] Build complete!
+
+$ ls -la --block-size=K .build/release/test
+-rwxr-xr-x 1 root root 17K Dec 3 22:48 .build/release/test*
+
+$ ldd .build/release/test
+ linux-vdso.so.1 (0x00007ffc82be4000)
+ libswift_Concurrency.so => /usr/lib/swift/linux/libswift_Concurrency.so (0x00007f0f5cfb5000)
+ libswiftCore.so => /usr/lib/swift/linux/libswiftCore.so (0x00007f0f5ca55000)
+ libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0f5c85e000)
+ libdispatch.so => /usr/lib/swift/linux/libdispatch.so (0x00007f0f5c7fd000)
+ libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f0f5c7da000)
+ libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f0f5c7d4000)
+ libswiftGlibc.so => /usr/lib/swift/linux/libswiftGlibc.so (0x00007f0f5c7be000)
+ libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f0f5c5dc000)
+ libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f0f5c48d000)
+ libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f0f5c472000)
+ /lib64/ld-linux-x86-64.so.2 (0x00007f0f5d013000)
+ libicui18nswift.so.65 => /usr/lib/swift/linux/libicui18nswift.so.65 (0x00007f0f5c158000)
+ libicuucswift.so.65 => /usr/lib/swift/linux/libicuucswift.so.65 (0x00007f0f5bf55000)
+ libicudataswift.so.65 => /usr/lib/swift/linux/libicudataswift.so.65 (0x00007f0f5a4a2000)
+ librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f0f5a497000)
+ libBlocksRuntime.so => /usr/lib/swift/linux/libBlocksRuntime.so (0x00007f0f5a492000)
+```
+
+Building the program with static linking of the Swift runtime libraries yields the following:
+
+```bash
+$ swift build -c release --static-swift-stdlib
+[3/3] Build complete!
+
+$ ls -la --block-size=K .build/release/test
+-rwxr-xr-x 1 root root 35360K Dec 3 22:50 .build/release/test*
+
+$ ldd .build/release/test
+ linux-vdso.so.1 (0x00007fffdaafa000)
+ libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fdd521c5000)
+ libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fdd521a2000)
+ libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fdd51fc0000)
+ libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fdd51e71000)
+ libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fdd51e56000)
+ libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fdd51c64000)
+ /lib64/ld-linux-x86-64.so.2 (0x00007fdd54211000)
+```
+
+These snippets demonstrates the following:
+1. Statically linking of the Swift runtime libraries increases the binary size from 17K to ~35M.
+2. Statically linking of the Swift runtime libraries reduces the dependencies reported by `ldd` to core Linux libraries.
+
+This jump in binary size may be alarming at first sight, but since the program is not usable without the Swift runtime libraries, the actual size of the deployable unit is similar.
+
+```bash
+$ mkdir deps
+
+$ ldd ".build/release/test" | grep swift | awk '{print $3}' | xargs cp -Lv -t ./deps
+'/usr/lib/swift/linux/libswift_Concurrency.so' -> './deps/libswift_Concurrency.so'
+'/usr/lib/swift/linux/libswiftCore.so' -> './deps/libswiftCore.so'
+'/usr/lib/swift/linux/libdispatch.so' -> './deps/libdispatch.so'
+'/usr/lib/swift/linux/libswiftGlibc.so' -> './deps/libswiftGlibc.so'
+'/usr/lib/swift/linux/libicui18nswift.so.65' -> './deps/libicui18nswift.so.65'
+'/usr/lib/swift/linux/libicuucswift.so.65' -> './deps/libicuucswift.so.65'
+'/usr/lib/swift/linux/libicudataswift.so.65' -> './deps/libicudataswift.so.65'
+'/usr/lib/swift/linux/libBlocksRuntime.so' -> './deps/libBlocksRuntime.so'
+
+$ ls -la --block-size=K deps/
+total 42480K
+drwxr-xr-x 2 root root 4K Dec 3 22:59 ./
+drwxr-xr-x 6 root root 4K Dec 3 22:58 ../
+-rw-r--r-- 1 root root 17K Dec 3 22:59 libBlocksRuntime.so
+-rw-r--r-- 1 root root 432K Dec 3 22:59 libdispatch.so
+-rwxr-xr-x 1 root root 27330K Dec 3 22:59 libicudataswift.so.65*
+-rwxr-xr-x 1 root root 4030K Dec 3 22:59 libicui18nswift.so.65*
+-rwxr-xr-x 1 root root 2403K Dec 3 22:59 libicuucswift.so.65*
+-rwxr-xr-x 1 root root 520K Dec 3 22:59 libswift_Concurrency.so*
+-rwxr-xr-x 1 root root 7622K Dec 3 22:59 libswiftCore.so*
+-rwxr-xr-x 1 root root 106K Dec 3 22:59 libswiftGlibc.so*
+```
+
+## Impact on existing packages
+
+The new behavior will take effect with a new version of SwiftPM, and packages build with that version will be linked accordingly.
+
+* Deployment of applications using "bag of shared objects" technique (#1 above) will continue to work as before (though would be potentially redundant).
+* Deployment of applications using explicit static linking (#2 above) will continue to work and emit a warning that its redundant.
+* Deployment of applications using docker "runtime" images (#3 above) will continue to work as before (though would be redundant).
+
+### Additional validation when linking libraries
+
+SwiftPM currently performs no validation when linking libraries into an executable that statically links the Swift runtime libraries.
+This means that users can mistakenly link a library that already has the Swift runtime libraries statically linked into the executable that will also statically link the Swift runtime libraries, which could lead to runtime errors if the versions of the Swift runtime libraries do not match.
+As part of this proposal, SwiftPM will gain a new post build validation checking for this condition and warning the user accordingly.
+
+## Alternatives considered and future directions
+
+The most obvious question this proposal brings is why not fully statically link the program instead of statically linking only the runtime libraries.
+Go is a good example for creating fully statically linked programs, contributing to its success in the server ecosystem at large.
+Swift already offers a flag for this linking mode: `-Xswiftc -static-executable`, but in reality Swift's ability to create fully statically linked programs is constrained.
+This is mostly because today, Swift on Linux only supports GNU's libc (Glibc) and GNU's C++ standard library which do not support producing fully static binaries.
+A future direction could be to look into supporting the `musl libc` and LLVM's `libc++` which should be able to produce fully static binaries.
+
+Further, Swift has good support to interoperate with C libraries installed on the system.
+Whilst that is a nice feature, it does make it difficult to create fully statically linked programs because it would be necessary to make sure each and every of these dependencies is available in a fully statically linked form with all the common dependencies being compatible.
+For example, it is not possible to link a binary that uses the `musl libc` with libraries that expect to be statically linked with Glibc.
+As Swift's ability to create fully statically linked programs improves, we should consider changing the default from `-Xswiftc -static-stdlib` to `-Xswiftc -static-executable`.
+
+A more immediate future direction which would improve programs that need to use of FoundationXML and FoundationNetworking is to replace the system dependencies of these modules with native implementation.
+This is outside the scope of this proposal which focuses on SwiftPM's behavior.
+
+Another alternative is to do nothing.
+In practice, this proposal does not add new features, it only changes default behavior which is already achievable with the right knowledge of build flags.
+That said, we believe that changing the default will make using Swift on non-Darwin platforms easier, saving time and costs to Swift users on such platforms.
+
+The spelling of the new flag `--disable-static-swift-runtime` is open to alternative ideas, e.g. `--disable-static-swift-runtime-libraries`.
diff --git a/proposals/0343-top-level-concurrency.md b/proposals/0343-top-level-concurrency.md
new file mode 100644
index 0000000000..e11e040563
--- /dev/null
+++ b/proposals/0343-top-level-concurrency.md
@@ -0,0 +1,213 @@
+# Concurrency in Top-level Code
+
+* Proposal: [SE-0343](0343-top-level-concurrency.md)
+* Authors: [Evan Wilde](https://github.com/etcwilde)
+* Review Manager: [Saleem Abdulrasool](https://github.com/compnerd)
+* Status: **Implemented (Swift 5.7)**
+* Implementation: [Fix top-level global-actor isolation crash](https://github.com/apple/swift/pull/40963), [Add `@MainActor @preconcurrency` to top-level variables](https://github.com/apple/swift/pull/40998), [Concurrent top-level inference](https://github.com/apple/swift/pull/41061)
+
+## Introduction
+
+Bringing concurrency to top-level code is an expected continuation of the
+concurrency work in Swift. This pitch looks to iron out the details of how
+concurrency will work in top-level code, specifically focusing on how top-level
+variables are protected from data races, and how a top-level code context goes
+from a synchronous context to an asynchronous context.
+
+Swift-evolution thread: [Discussion thread topic for concurrency in top-level code](https://forums.swift.org/t/concurrency-in-top-level-code/55001)
+
+## Motivation
+
+The top-level code declaration context works differently than other declaration
+spaces. As such, adding concurrency features to this spaces results in questions
+that have not yet been addressed.
+
+Variables in top-level code behave as a global-local hybrid variable; they exist
+in the global scope and are accessible as global variables within the module,
+but are initialized sequentially like local variables. Global variables are
+dangerous, especially with concurrency. There are no isolation guarantees made,
+and are therefore subject to race conditions.
+
+As top-level code is intended as a safe space for testing out features and
+writing pleasant little scripts, this simply will not do.
+
+In addition to the strange and dangerous behavior of variables, changing whether
+a context is synchronous or asynchronous has an impact on how function overloads
+are resolved, so simply flipping a switch could result in some nasty hidden
+semantic changes, potentially breaking scripts that already exist.
+
+## Proposed solution
+
+The solutions will only apply when the top-level code is an asynchronous
+context. As a synchronous context, the behavior of top-level code does not
+change. In order to trigger making the top-level context an asynchronous context, I
+propose using the presence of an `await` in one of the top-level expressions.
+
+An await nested within a function declaration or a closure will not trigger the
+behavior.
+
+```swift
+func doAsyncStuff() async {
+ // ...
+}
+
+let countCall = 0
+
+let myClosure = {
+ await doAsyncStuff() // `await` does not trigger async top-level
+ countCall += 1
+}
+
+await myClosure() // This `await` will trigger an async top-level
+```
+
+Top-level global variables are implicitly assigned a `@MainActor` global actor
+isolation to prevent data races. To avoid breaking sources, the variable is
+implicitly marked as pre-concurrency up to Swift 6.
+
+```swift
+var a = 10
+
+func bar() {
+ print(a)
+}
+
+bar()
+
+await something() // make top-level code an asynchronous context
+```
+
+After Swift 6, full actor-isolation checking will take place. The usage of `a`
+in `bar` will result in an error due to `bar` not being isolated to the
+`MainActor`. In Swift 5, this will compile without errors.
+
+## Detailed design
+
+### Asynchronous top-level context inference
+
+The rules for inferring whether the top-level context is an asynchronous context
+are the same for anonymous closures, specified in [SE-0296 Async/Await](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0296-async-await.md#closures).
+
+The top-level code is inferred to be an asynchronous context if it contains a
+suspension point in the immediate top-level context.
+
+```swift
+func theAnswer() async -> Int { 42 }
+
+async let a = theAnswer() // implicit await, top-level is async
+
+await theAnswer() // explicit await, top-level is async
+
+let numbers = AsyncStream(Int.self) { continuation in
+ Task {
+ for number in 0 .. < 10 {
+ continuation.yield(number)
+ }
+ continuation.finish()
+ }
+}
+
+for await number in numbers { // explicit await, top-level is asnyc
+ print(number)
+}
+```
+
+The above example demonstrates each kind of suspension point, triggering an
+asynchronous top-level context. Specifically, `async let a = theAnswer()`
+involves an implicit suspension, `await theAnswer()` involves an explicit
+suspension, as does `for await number in numbers`. Any one of these is
+sufficient to trigger the switch to an asynchronous top-level context.
+
+Not that the inference of `async` in the top-level does not propagate to
+function and closure bodies, because those contexts are separably asynchronous
+or synchronous.
+
+```swift
+func theAnswer() async -> Int { 42 }
+
+let closure1 = { @MainActor in print(42) }
+let closure2 = { () async -> Int in await theAnswer() }
+```
+
+The top-level code in the above example is not an asynchronous context because
+the top-level does not contain a suspension point, either explicit or implicit.
+
+The mechanism for inferring whether a closure body is an asynchronous context
+lives in the `FindInnerAsync` ASTWalker. With minimal effort, the
+`FindInnerAsync` walker can be generalized to handle top-level code bodies,
+maintaining the nice parallel inference behaviour between top-level code and
+closure body asynchronous detection.
+
+### Variables
+
+Variables in top-level code are initialized sequentially like a local variable,
+but are in the global scope and are otherwise treated as global variables. To
+prevent data races, variables should implicitly be isolated to the main actor.
+It would be a shame if every top-level variable access had to go through an
+`await` though. Luckily, like the other entrypoints, top-level code runs on the
+main thread, so we can make the top-level code space implicitly main-actor
+isolated so the variables can be accessed and modified directly. This is still
+source-breaking though; a synchronous global function written in the top-level
+code will emit an error because the function is not isolated to the main actor
+when the variable is. While the diagnostic is correct in stating that there is a
+potential data-race, the source-breaking effect is also unfortunate. To
+alleviate the source break, the variable is implicitly annotated with the
+`@preconcurrency` attribute. The attribute only applies to Swift 5 code, and
+once the language mode is updated to Swift 6, these data races will become hard
+errors.
+
+If `-warn-concurrency` is passed to the compiler and there is an `await` in
+top-level code, the warnings are hard errors in Swift 5, as they would in any
+other asynchronous context. If there is no `await` and the flag is passed,
+variables are implicitly protected by the main actor and concurrency checking is
+strictly enforced, even though the top-level is not an asynchronous context.
+Since the top-level is not an asynchronous context, no run-loops are created
+implicitly and the overload resolution behavior does not change.
+
+In summary, top-level variable declarations behave as though they were declared
+with `@MainActor @preconcurrency` in order to strike a nice balance between
+data-race safety and reducing source breaks.
+
+Going back to the global behaviour variables, there are some additional design
+details that I should point out.
+
+I would like to propose removing the ability to explicitly specify a global
+actor on top-level variables. Top-level variables are treated like a hybrid of
+global and local variables, which has some nasty consequences. The variables are
+declared in the global scope, so they are assumed to be available anywhere. This
+results in some nasty memory safety issues, like the following example:
+
+```swift
+print(a)
+let a = 10
+```
+
+The example compiles and prints "0" when executed. The declaration `a` is
+available at the `print` statement because it is a global variable, but it is
+not yet initialized because initialization happens sequentially. Integer types
+and other primitives are implicitly zero-initialized; however, classes are
+referential types, initialized to zero, so this results in a segmentation fault
+if the variable is a class type.
+
+Eventually, we would like to plug this hole in the memory model. The design for
+that is still in development, but will likely move toward making top-level
+variables local variables of the implicit main function. I am proposing that we
+disallow explicit global actors to facilitate that change and reduce the source
+breakage caused by that change.
+
+## Source compatibility
+
+The `await` expression cannot appear in top-level code today since the top-level
+is not an asynchronous context. As the features proposed herein are enabled by
+the presence of an `await` expression in the top level, there are no scripts
+today that will be affected by the changes proposed in this proposal.
+
+## Effect on ABI stability
+
+This proposal has no impact on ABI. Functions and variables have the same
+signature as before.
+
+## Acknowledgments
+
+Thank you, Doug, for lots of discussion on how to break this down into something
+that minimizes source breakage to a level where we can introduce this to Swift 5.
diff --git a/proposals/0344-distributed-actor-runtime.md b/proposals/0344-distributed-actor-runtime.md
new file mode 100644
index 0000000000..b052a3531c
--- /dev/null
+++ b/proposals/0344-distributed-actor-runtime.md
@@ -0,0 +1,1888 @@
+# Distributed Actor Runtime
+
+* Proposal: [SE-0344](0344-distributed-actor-runtime.md)
+* Authors: [Konrad 'ktoso' Malawski](https://github.com/ktoso), [Pavel Yaskevich](https://github.com/xedin), [Doug Gregor](https://github.com/DougGregor), [Kavon Farvardin](https://github.com/kavon), [Dario Rexin](https://github.com/drexin), [Tomer Doron](https://github.com/tomerd)
+* Review Manager: [Joe Groff](https://github.com/jckarter/)
+* Status: **Implemented (Swift 5.7)**
+* Implementation:
+ * Partially available in [recent `main` toolchain snapshots](https://swift.org/download/#snapshots) behind the `-enable-experimental-distributed` feature flag.
+ * This flag also implicitly enables `-enable-experimental-concurrency`.
+* Review threads
+ * [First Review](https://forums.swift.org/t/se-0344-distributed-actor-runtime/55525) ([summary](https://forums.swift.org/t/returned-for-revision-se-0344-distributed-actor-runtime/55836))
+ * [Second Review](https://forums.swift.org/t/se-0344-second-review-distributed-actor-runtime/56002) ([summary](https://forums.swift.org/t/accepted-se-0344-distributed-actor-runtime/56416))
+
+
+## Table of Contents
+
+- [Distributed Actor Runtime](#distributed-actor-runtime)
+ - [Table of Contents](#table-of-contents)
+ - [Introduction](#introduction)
+ - [Useful links](#useful-links)
+ - [Motivation](#motivation)
+ - [Example scenario](#example-scenario)
+ - [Caveat: Low-level implementation details](#caveat-low-level-implementation-details)
+ - [Detailed design](#detailed-design)
+ - [The `DistributedActorSystem` protocol](#the-distributedactorsystem-protocol)
+ - [Implicit distributed actor properties](#implicit-distributed-actor-properties)
+ - [Initializing distributed actors](#initializing-distributed-actors)
+ - [Distributed actor initializers](#distributed-actor-initializers)
+ - [Initializing `actorSystem` and `id` properties](#initializing-actorsystem-and-id-properties)
+ - [Ready-ing distributed actors](#ready-ing-distributed-actors)
+ - [Ready-ing distributed actors, exactly once](#ready-ing-distributed-actors-exactly-once)
+ - [Resigning distributed actor IDs](#resigning-distributed-actor-ids)
+ - [Resolving distributed actors](#resolving-distributed-actors)
+ - [Invoking distributed methods](#invoking-distributed-methods)
+ - [Sender: Invoking a distributed method](#sender-invoking-a-distributed-method)
+ - [Sender: Serializing and sending invocations](#sender-serializing-and-sending-invocations)
+ - [Recipient: Receiving invocations](#recipient-receiving-invocations)
+ - [Recipient: Deserializing incoming invocations](#recipient-deserializing-incoming-invocations)
+ - [Recipient: Resolving the recipient actor instance](#recipient-resolving-the-recipient-actor-instance)
+ - [Recipient: The `executeDistributedTarget` method](#recipient-the-executedistributedtarget-method)
+ - [Recipient: Executing the distributed target](#recipient-executing-the-distributed-target)
+ - [Recipient: Collecting result/error from invocations](#recipient-collecting-resulterror-from-invocations)
+ - [Amendments](#amendments)
+ - [Initializers no longer need to accept a single DistributedActorSystem](#initializers-no-longer-need-to-accept-a-single-distributedactorsystem)
+ - [Future work](#future-work)
+ - [Variadic generics removing the need for `remoteCallVoid`](#variadic-generics-removing-the-need-for-remotecallvoid)
+ - [Identifying, evolving and versioning remote calls](#identifying-evolving-and-versioning-remote-calls)
+ - [Default distributed call target identification scheme](#default-distributed-call-target-identification-scheme)
+ - [Compression techniques to avoid repeatedly sending large identifiers](#compression-techniques-to-avoid-repeatedly-sending-large-identifiers)
+ - [Overlap with general ABI and versioning needs in normal Swift code](#overlap-with-general-abi-and-versioning-needs-in-normal-swift-code)
+ - [Discussion: User provided target identities](#discussion-user-provided-target-identities)
+ - [Resolving `DistributedActor` protocols](#resolving-distributedactor-protocols)
+ - [Passing parameters to `assignID`](#passing-parameters-to-assignid)
+ - [Alternatives considered](#alternatives-considered)
+ - [Define `remoteCall` as protocol requirement, and accept `[Any]` arguments](#define-remotecall-as-protocol-requirement-and-accept-any-arguments)
+ - [Constraining arguments, and return type with of `remoteCall` with `SerializationRequirement`](#constraining-arguments-and-return-type-with-of-remotecall-with-serializationrequirement)
+ - [Hardcoding the distributed runtime to make use of `Codable`](#hardcoding-the-distributed-runtime-to-make-use-of-codable)
+ - [Acknowledgments & Prior art](#acknowledgments--prior-art)
+ - [Source compatibility](#source-compatibility)
+ - [Effect on ABI stability](#effect-on-abi-stability)
+ - [Effect on API resilience](#effect-on-api-resilience)
+ - [Changelog](#changelog)
+
+## Introduction
+
+With the recent introduction of [actors](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0306-actors.md) to the language, Swift gained powerful and foundational building blocks for expressing *thread-safe* concurrent programs. Actors guarantee thread-safety thanks to actor-isolation of mutable state they encapsulate.
+
+In [SE-0336: Distributed Actor Isolation][isolation] we took it a step further, guaranteeing complete isolation of state with distributed actor-isolation, and setting the stage for `distributed` method calls to be performed across process and node boundaries.
+
+This proposal focuses on the runtime aspects of making such remote calls possible, their exact semantics and how developers can provide their own `DistributedActorSystem` implementations to hook into the same language mechanisms, extending Swift's distributed actor model to various environments (such as cross-process communication, clustering, or even client/server communication).
+
+#### Useful links
+
+It is recommended, though not required, to familiarize yourself with the prior proposals before reading this one:
+
+- [SE-0336: Distributed Actor Isolation][isolation] — a detailed proposal
+- Distributed Actor Runtime (this proposal)
+
+Feel free to reference the following library implementations which implement this proposal's library side of things:
+
+- [Swift Distributed Actors Library](https://www.swift.org/blog/distributed-actors/) — a reference implementation of a *peer-to-peer cluster* for distributed actors. Its internals depend on the work in progress language features and are dynamically changing along with these proposals. It is a realistic implementation that we can use as reference for these design discussions.
+
+## Motivation
+
+With distributed actor-isolation checking laid out in [SE-0336: Distributed Actor Isolation][isolation], we took the first step towards enabling remote calls being made by invoking `distributed func` declarations on distributed actors. The isolation model and serialization requirement checks in that proposal outline how we can guarantee the soundness of such distributed actor model at compile time.
+
+Distributed actors enable developers to build their applications and systems using the concept of actors that may be "local" or "remote", and communicate with them regardless of their location. Our goal is to set developers free from having to re-invent ad-hoc approaches to networking, serialization and error handling every time they need to embrace distributed computing.
+
+Instead, we aim to embrace a co-operative approach to the problem, in which:
+
+1. the Swift language, compiler, and runtime provide the necessary isolation checks and runtime hooks for distributed actor lifecycle management, and distributed method calls that can be turned into "messages" that can be sent to remote peers,
+2. `DistributedActorSystem` library implementations, hook into the language provided cut-points, take care of the actual message interactions, e.g. by sending messages representing remote distributed method calls over the network,
+3. `distributed actor` authors, who want to focus on getting things done, express their distributed API boundaries and communicate using them. They may have opinions about serialization and specifics of message handling, and should be able to configure and use the `DistributedActorSystem` of their choice to get things done.
+
+In general, we propose to embrace the actor style of communication for typical distributed system development, and aim to provide the necessary tools in the language, and runtime to make this a pleasant and nice default go-to experience for developers.
+
+Distributed actors may not serve *all* possible use-cases where networking is involved, but we believe a large group of applications and systems will benefit from them, as the ecosystem gains mature `DistributedActorSystem` implementations.
+
+#### Example scenario
+
+In this proposal we will focus only on the runtime aspects of distributed actors and methods, i.e. what happens in order to create, send, and receive messages formed when a distributed method is called on a remote actor. For more details on distributed actor isolation and other compile-time checks, please refer to [SE-0336: Distributed Actor Isolation][isolation].
+
+We need to pass around distributed actors in order to invoke methods on them at some later point in time. We need those actors to declare `distributed` methods such that we have something we can message them with, and there must be some lifecycle and registration mechanisms related to them.
+
+One example use case we can keep in mind is a simple turn-based `Game` which showcases most of the capabilities we come to expect of distributed actors:
+
+```swift
+distributed actor Player {
+ // ...
+
+ distributed func makeMove() -> Move { ... }
+
+ distributed func gameFinished(result: GameResult) {
+ if result.winner == self {
+ print("I WON!")
+ } else {
+ print("Player \(result.winner) won the game.")
+ }
+ }
+}
+
+distributed actor Game {
+ var state: GameState = ...
+
+ // players can be located on different nodes
+ var players: Set = []
+
+ distributed func playerJoined(_ player: Player) {
+ others.append(player)
+ if others.count >= 2 { // we need 2 other players to start a game
+ Task { try await self.start() }
+ }
+ }
+
+ func start() async throws {
+ state = .makeNewGameState(with: players)
+ while !state.finished {
+ for player in players {
+ let move = try await p.makeMove() // TODO: handle failures, e.g. "move timed-out"
+ state.apply(move, by: player)
+ }
+ }
+
+ let winner = state.winner
+ try await game.finishedResult
+ }
+}
+```
+
+This code snippet showcases what kind of distributed actors one might want to implement – they represent addressable identities in a system where players may be hosted on different hosts or devices, and we'd like to communicate with any of them from the `Game` actor which manages the entire game's state. Players may be on the same host as the `Game` actor, or on different ones, but we never have to change the implementation of `Game` to deal with this – thanks to distributed actors and the concept of location transparency, we can implement this piece of code once, and run it all locally, or distributed without changing the code specifically for either of those cases.
+
+### Caveat: Low-level implementation details
+
+This proposal includes low-level implementation details in order to showcase how one can use to build a real, efficient, and extensible distributed actor system using the proposed language runtime. It is primarily written for distributed actor system authors, which need to understand the underlying mechanisms which distributed actors use.
+
+End users, who just want to use _distributed actors_, and not necessarily _implement_ a distributed actor system runtime, do not need to dive deep as deep into this proposal, and may be better served by reading [SE-0366: Distributed Actor Isolation][isolation] which focuses on how distributed actors are used. Reading this — runtime — proposal, however, will provide additional insights as to why distributed actors are isolated the way they are.
+
+This proposal focuses on how a distributed actor system runtime can be implemented. Because this language feature is extensible, library authors may step in and build their own distributed actor runtimes. It is expected that there will be relatively few, but solid actor system implementations eventually, yet their use would apply to many many more end-users than actor system developers.
+
+## Detailed design
+
+This section is going to deep dive into the runtime details and its interaction with user provided `DistributedActorSystem` implementations. Many of these aspects are not strictly necessary to internalize by end-user/developer, who only wants to write some distributed actors and have them communicate using *some* distributed actor system.
+
+### The `DistributedActorSystem` protocol
+
+At the core of everything distributed actors do, is the `DistributedActorSystem` protocol. This protocol is open to be implemented by anyone, and can be used to extend the functionality of distributed actors to various environments.
+
+Building a solid actor system implementation is not a trivial task, and we only expect a handful of mature implementations to take the stage eventually.
+
+> At the time of writing, we–the proposal authors–have released a work in progress [peer-to-peer cluster actor system implementation](https://www.swift.org/blog/distributed-actors/) that is tracking this evolving language feature. It can be viewed as a reference implementation for the language features and `DistributedActorSystem` protocol discussed in this proposal.
+
+Below we present the full listing of the `DistributedActorSystem` protocol, and we'll be explaining the specific methods one by one as we go:
+
+```swift
+// Module: _Distributed
+
+protocol DistributedActorSystem: Sendable {
+ /// The type of `ID` assigned to a distributed actor while initializing with this actor system.
+ /// The identity should be meaningfully unique, in the sense that ID equality should mean referring to the
+ /// same distributed actor.
+ ///
+ /// A distributed actor created using a specific actor system will use the system's `ActorID` as
+ /// the `ID` type it stores and for its `Hashable` implementation.
+ ///
+ /// ### Implicit distribute actor `Codable` conformance
+ /// If the `ActorID` (and therefore also the `DistributedActor.ID`) conforms to `Codable`,
+ /// the `distributed actor` will gain an automatically synthesized conformance to `Codable` as well.
+ associatedtype ActorID: Sendable & Hashable
+
+ /// The specific type of the invocation encoder that will be created and populated
+ /// with details about the invocation when a remote call is about to be made.
+ ///
+ /// The populated instance will be passed to the `remoteCall` from where it can be
+ /// used to serialize into a message format in order to perform the remote invocation.
+ associatedtype InvocationEncoder: DistributedTargetInvocationEncoder
+
+ /// The specific type of invocation decoder used by this actor system.
+ ///
+ /// An instance of this type must be passed to `executeDistributedTarget` which
+ /// extracts arguments and applies them to the local target of the invocation.
+ associatedtype InvocationDecoder: DistributedTargetInvocationDecoder
+
+ /// The serialization requirement that will be applied to all distributed targets used with this system.
+ ///
+ /// An actor system is still allowed to throw serialization errors if a specific value passed to a distributed
+ /// func violates some other restrictions that can only be checked at runtime, e.g. checking specific types
+ /// against an "allow-list" or similar. The primary purpose of the serialization requirement is to provide
+ /// compile time hints to developers, that they must carefully consider evolution and serialization of
+ /// values passed to and from distributed methods and computed properties.
+ associatedtype SerializationRequirement
+ where SerializationRequirement == InvocationEncoder.SerializationRequirement,
+ SerializationRequirement == InvocationDecoder.SerializationRequirement
+
+ // ==== ---------------------------------------------------------------------
+ // - MARK: Actor Lifecycle
+
+ /// Called by a distributed when it begins its initialization (in a non-delegating init).
+ ///
+ /// The system should take special care to not assign two actors the same `ID`, and the `ID`
+ /// must remain valid until it is resigned (see `resignID(_:)`).
+ func assignID(_ actorType: Actor.Type) -> ActorID
+ where Actor: DistributedActor,
+ Actor.ID == ActorID
+
+ /// Automatically called by in every distributed actor's non-delegating initializer.
+ ///
+ /// The call is made specifically before the `self` of such distributed actor is about to
+ /// escape, e.g. via a function call, closure or otherwise. If no such event occurs the
+ /// call is made at the end of the initializer.
+ ///
+ /// The passed `actor` is the `self` of the initialized actor, and its `actor.id` is expected
+ /// to be of the same value that was assigned to it in `assignID`.
+ ///
+ /// After the ready call returns, it must be possible to resolve it using the 'resolve(_:as:)'
+ /// method on the system.
+ func actorReady(_ actor: Actor)
+ where Actor: DistributedActor,
+ Actor.ID == ActorID
+
+ /// Called when the distributed actor is deinitialized (or has failed to finish initializing).
+ ///
+ /// The system may release any resources associated with this actor id, and should not make
+ /// further attempts to deliver messages to the actor identified by this identity.
+ func resignID(_ id: ActorID)
+
+ // ==== ---------------------------------------------------------------------
+ // - MARK: Resolving distributed actors
+
+ /// Resolve a local or remote actor address to a real actor instance, or throw if unable to.
+ /// The returned value is either a local actor or proxy to a remote actor.
+ ///
+ /// Resolving an actor is called when a specific distributed actors `init(from:)`
+ /// decoding initializer is invoked. Once the actor's identity is deserialized
+ /// using the `decodeID(from:)` call, it is fed into this function, which
+ /// is responsible for resolving the identity to a remote or local actor reference.
+ ///
+ /// If the resolve fails, meaning that it cannot locate a local actor managed for
+ /// this identity, managed by this transport, nor can a remote actor reference
+ /// be created for this identity on this transport, then this function must throw.
+ ///
+ /// If this function returns correctly, the returned actor reference is immediately
+ /// usable. It may not necessarily imply the strict *existence* of a remote actor
+ /// the identity was pointing towards, e.g. when a remote system allocates actors
+ /// lazily as they are first time messaged to, however this should not be a concern
+ /// of the sending side.
+ ///
+ /// Detecting liveness of such remote actors shall be offered / by transport libraries
+ /// by other means, such as "watching an actor for termination" or similar.
+ func resolve(_ id: ActorID, as actorType: Actor.Type) throws -> Actor?
+ where Actor: DistributedActor,
+ Actor.ID: ActorID,
+ Actor.SerializationRequirement == Self.SerializationRequirement
+
+ // ==== ---------------------------------------------------------------------
+ // - MARK: Remote Target Invocations
+
+ /// Invoked by the Swift runtime when a distributed remote call is about to be made.
+ ///
+ /// The returned `InvocationEncoder` will be populated with all
+ /// generic substitutions, arguments, and specific error and return types
+ /// that are associated with this specific invocation.
+ func makeInvocationEncoder() -> InvocationEncoder
+
+ // We'll discuss the remoteCall method in detail in this proposal.
+ // It cannot be declared as protocol requirement, and remains an ad-hoc
+ // requirement like this:
+ /// Invoked by the Swift runtime when making a remote call.
+ ///
+ /// The `invocation` is the arguments container that was previously created
+ /// by `makeInvocationEncoder` and has been populated with all arguments.
+ ///
+ /// This method should perform the actual remote function call, and await for its response.
+ ///
+ /// ## Errors
+ /// This method is allowed to throw because of underlying transport or serialization errors,
+ /// as well as by re-throwing the error received from the remote callee (if able to).
+ ///
+ /// Ad-hoc protocol requirement.
+ func remoteCall(
+ on actor: Actor,
+ target: RemoteCallTarget,
+ invocation: inout InvocationEncoder,
+ throwing: Failure.Type,
+ returning: Success.Type
+ ) async throws -> Success
+ where Actor: DistributedActor,
+ Actor.ID == ActorID,
+ Failure: Error,
+ Success: Self.SerializationRequirement
+
+ /// Invoked by the Swift runtime when making a remote call to a `Void` returning function.
+ ///
+ /// ( ... Same as `remoteCall` ... )
+ ///
+ /// Ad-hoc protocol requirement.
+ func remoteCallVoid(
+ on actor: Actor,
+ target: RemoteCallTarget,
+ invocation: inout InvocationEncoder,
+ throwing: Failure.Type
+ ) async throws
+ where Actor: DistributedActor,
+ Actor.ID == ActorID,
+ Failure: Error
+}
+
+/// A distributed 'target' can be a `distributed func` or `distributed` computed property.
+///
+/// The actor system should encode the identifier however it sees fit,
+/// and transmit it to the remote peer in order to invoke identify the target of an invocation.
+public struct RemoteCallTarget: Hashable {
+ /// The mangled name of the invoked distributed method.
+ ///
+ /// It contains all information necessary to lookup the method using `executeDistributedActorMethod(...)`
+ var mangledName: String { ... }
+
+ /// The human-readable "full name" of the invoked method, e.g. 'Greeter.hello(name:)'.
+ var fullName: String { ... }
+}
+```
+
+In the following sections, we will be explaining how the various methods of a distributed system are invoked by the Swift runtime.
+
+### Implicit distributed actor properties
+
+Distributed actors have two properties that are crucial for the inner workings of actors that we'll explore during this proposal: the `id` and `actorSystem`.
+
+These properties are synthesized by the compiler, in every `distributed actor` instance, and they witness the `nonisolated` property requirements defined on the `DistributedActor` protocol.
+
+The `DistributedActor` protocol (defined in [SE-0336][isolation]), defines those requirements:
+
+```swift
+protocol DistributedActor {
+ associatedtype ActorSystem: DistributedActorSystem
+
+ typealias ID = ActorSystem.ActorID
+ typealias SerializationRequirement: ActorSystem.SerializationRequirement
+
+ nonisolated var id: ID { get }
+ nonisolated var actorSystem: ActorSystem { get }
+
+ // ...
+}
+```
+
+which are witnessed by *synthesized properties* in every specific distributed actor instance.
+
+Next, we will discuss how those properties get initialized, and used in effectively all aspects of a distributed actor's lifecycle.
+
+### Initializing distributed actors
+
+At runtime, a *local* `distributed actor` is effectively the same as a local-only `actor`. The allocated `actor` instance is a normal `actor`. However, its initialization is a little special, because it must interact with its associated actor system to make itself available for remote calls.
+
+We will focus on non-delegating initializers, as they are the ones where distributed actors cause additional things to happen.
+
+> Please note that **initializing** a distributed actor with its `init` always returns a **local** reference to a new actor. The only way to obtain a a remote reference is by using the `resolve(id:using:)` method, which is discussed in [Resolving Distributed Actors](#resolving-distributed-actors).
+
+Distributed actor initializers inject a number of calls into specific places of the initializer's body. These calls allow for the associated actor system to manage the actor's identity, and availability to remote calls. Before we dive into the details, the following diagram outlines the various calls that will be explained in this section:
+
+```
+┌────────────────────────────┐ ┌──────────────────────────┐
+│ distributed actor MyActor │ │ MyDistributedActorSystem │
+└────────────────────────────┘ └──────────────────────────┘
+ │ │
+ init(...) │
+ │ │
+ │── // self.id = actorSystem.assignID(Self.self) ───▶│ Generate and reserve ID
+ │ │
+ │ // self.actorSystem = system │
+ │ │
+ │ │
+ │ │
+ │── // actorSystem.actorReady(self) ────────────────▶│ Store a mapping (ID -> some DistributedActor)
+ │ │
+ ... ...
+ │ │
+ ◌ deinit ─ // actorSystem.resignID(self.id) ────────▶│ Remove (ID -> some DistributedActor) mapping
+ │
+ ...
+```
+
+### Distributed actor initializers
+
+A non-delegating initializer of a type must *fully initialize* it. The place in code where an actor becomes fully initialized has important and specific meaning to actor isolation which is defined in depth in [SE-0327: On Actors and Initialization](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0327-actor-initializers.md). Not only that, but once fully initialized it is possible to escape `self` out of a (distributed) actor's initializer. This aspect is especially important for distributed actors, because it means that once fully initialized they _must_ be registered with the actor system as they may be sent to other distributed actors and even sent messages to.
+
+All non-delegating initializers must store an instance of a `DistributedActorSystem` conforming type into their `self.actorSystem` property.
+
+This is an improvement over the initially proposed semantics in [SE-0336: Distributed Actor Isolation][isolation], where the initializers must have accepted a _single_ distributed actor system argument and would initialize the synthesized stored property automatically.
+
+This proposal amends this behavior to the following semantics:
+
+- the default initializer gains a `actorSystem: Self.ActorSystem` parameter.
+- other non-delegating initializers must initialize the `self.actorSystem` property explicitly.
+ - it is recommended to accept an actor system argument and store it
+ - technically it is also possible to store a global actor system to this property, however this is generally an anti-pattern as it hurts testability of such actor (i.e. it becomes impossible to swap the actor system for a "for testing" one during test execution).
+
+```swift
+distributed actor DA {
+ // synthesized:
+ // init(actorSystem: Self.ActorSystem) {} // ✅ no user defined init, so we synthesize a default one
+}
+
+distributed actor DA2 {
+ init(system: Self.ActorSystem) { // ⚠️ ok declaration, but self.actorSystem was not initialized
+ // ❌ error: implicit stored property 'actorSystem' was not initialized
+ }
+
+ init(other: Int, actorSystem system: Self.ActorSystem) { // ✅ ok
+ self.actorSystem = system
+ }
+}
+```
+
+Now in the next sections, we will explore in depth why this parameter was necessary to enforce to begin with.
+
+#### Initializing `actorSystem` and `id` properties
+
+The two properties (`actorSystem` and `id`) are synthesized _stored_ properties in the body of every actor.
+
+Users must initialize the `actorSystem`, however management of the `id` is left up to the compiler to synthesize. All properties of an actor have to be initialized for the type to become fully initialized, same as with any other type. However, the initialization of `id` is left to the compiler in order to streamline the initialization, as well as keep the _strict_ contract between the stored actor system and that the `ID` _must_ be assigned by that exact actor system. It would be illegal to just assign an `id` from some other source because of how tightly it relates to the actors lifecycle.
+
+The compiler synthesizes code that does this in any designated initializer of distributed actors:
+
+```swift
+distributed actor DA {
+ // let id: ID
+ // let actorSystem: ActorSystem
+
+ init(actorSystem: Self.ActorSystem) {
+ self.actorSystem = actorSystem
+ // ~~~ synthesized ~~~
+ // ...
+ // ~~~ end of synthesized ~~~
+ }
+}
+```
+
+Synthesizing the id assignment means that we need to communicate with the `system` used to initialize the distributed actor, for it is the `ActorSystem` that allocates and manages identifiers. In order to obtain a fresh `ID` for the actor being initialized, we need to call `system`'s `assignID` method. This is done before any user-defined code is allowed to run in the actors designated initializer, like this:
+
+```swift
+distributed actor DA {
+ let number: Int
+
+ init(system: ActorSystem) {
+ self.actorSystem = system
+ // ~~ injected property initialization ~~
+ // self.id = system.assignID(Self.self)
+ // ~~ end of injected property initialization ~~
+
+ // user-defined code follows...
+ self.number = 42
+
+ // ...
+ }
+}
+```
+
+### Ready-ing distributed actors
+
+So far, the initialization process was fairly straightforward. We only needed to find a way to initialize the stored properties, and that's it. There is one more step though that is necessary to make distributed actors work: "ready-ing" the actor.
+
+As the actor becomes fully initialized, the type system allows escaping its `self` through method calls or closures. There are a number of rules which govern the isolation state of `self` of any actor during its initializer, which are fully explained in: [SE-0327: On Actor Initialization](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0327-actor-initializers.md). Distributed actor initializers are subject to the same rules, and in addition to that they inject an `actorReady(self)` at the point where self would have become nonisolated under the rules explained in SE-0327.
+
+This call is necessary in order for the distributed actor system to be able to resolve an incoming `ID` (that it knows, since it assigned it) to a specific distributed actor instance (which it does not know, until `actorReady` is called on the system). This means that there is a state between the `assignID` and `actorReady` calls, during which the actor system cannot yet properly resolve the actor.
+
+A distributed actor becomes "ready", and transparently invokes `actorSystem.ready(self)`, during its non-delegating initializer just _before_ the actor's `self` first escaping use, or at the end of the initializer if no explicit escape is found.
+
+This rule is not only simple to remember, but also consistent between synchronous and asynchronous initializers. The rule plays also very well with the flow-isolation treatment of self in plain actors.
+
+The following snippets illustrate where the ready call is emitted by the compiler:
+
+```swift
+distributed actor DA {
+ let number: Int
+
+ init(sync system: ActorSystem) {
+ self.actorSystem = system
+ // << self.id = system.assignID(Self.self)
+ self.number = 42
+ // << system.actorReady(self)
+ }
+
+ init(sync system: ActorSystem) {
+ self.actorSystem = system
+ // << self.id = system.assignID(Self.self)
+ self.number = 42
+ // << system.actorReady(self)
+ Task.detached { // escaping use of `self`
+ await self.hello()
+ }
+ }
+}
+```
+
+If the self of the actor were to be escaped on multiple execution paths, the ready call is injected in all appropriate paths, like this:
+
+```swift
+distributed actor DA {
+ let number: Int
+ init(number: Int, system: ActorSystem) async {
+ self.actorSystem = system
+ // << self.id = system.assignID(Self.self)
+ if number % 2 == 0 {
+ print("even")
+ self.number = number
+ // << system.actorReady(self)
+ something(self)
+ } else {
+ print("odd")
+ self.number = number
+ // << system.actorReady(self)
+ something(self)
+ }
+ }
+}
+```
+
+Special care needs to be taken about the distributed actor and actor system interaction in the time between the `assignID` and `actorReady` calls, because during this time the system is unable to *deliver* an invocation to the target actor. However, it is always able to recognize that an ID is known, but just not ready yet – the system did create and assign the ID after all.
+
+This should not be an issue for developers using distributed actors, but actor system authors need to be aware of this interval between the actor ID being reserved and readies. We suggest "reserving" the ID immediately in `assignID` in order to avoid issuing the same ID to multiple actors which can yield unexpected behavior when handling incoming messages.
+
+Another thing to be aware of is "long" initializers, which take a long time to complete which may sometimes be the case with asynchronous initializers. For example, consider this initializer which performs a lot of work on the passed in items before returning:
+
+```swift
+init(items: [Item], system: ActorSystem) async {
+ self.actorSystem = system
+ // << self.id = system.assignID(Self.self)
+ for await item in items {
+ await compute(item)
+ }
+ // ...
+ // ...
+ // ?? what if init "never" returns" ??
+ // ...
+ // ...
+ // << system.actorReady(self)
+}
+```
+
+This is arguably problematic for any class, struct or actor, however for distributed actors this also means that the period of time during an ID was assigned and will finally be readied can be potentially quite long. In general, we discourage such "long running" initializers as they make use of the actor in distribution impossible until it is readied. On the other hand, though, it can only be used in distribution once the initializer returns in any case so this is a similar problem to any long running initializer.
+
+#### Ready-ing distributed actors, exactly once
+
+Another interesting case the `actorReady` synthesis in initializers needs to take care of is triggering the `actorReady` call only *once*, as the actor first becomes fully initialized. The following snippet does a good job showing an example of where it can manifest:
+
+```swift
+distributed actor DA {
+ var int: Int
+ init(system: ActorSystem) async {
+ self.actorSystem = system
+ var loops = 10
+ while loops > 0 {
+ self.int = loops
+ // ~ AT THE FIRST ITERATION ~
+ // ~ become fully initialized ~
+ // ...
+ escape(self)
+
+ loops -= 1
+ }
+ }
+}
+```
+
+This actor performs a loop during which it assigns values to `self.int`, the actor becomes fully initialized the first time this loop runs.
+
+We need to emit the `actorReady(self)` call, only once, and we should not repeatedly call the actor system's `actorReady` method which would force system developers into weirdly defensive implementations of this method. Thankfully, this is possible to track in the compiler, and we can emit the ready call only once, based on internal initialization marking mechanisms (that store specific bits for every initialized field).
+
+The synthesized (pseudo-)code therefore is something like this:
+
+```swift
+distributed actor DA {
+ var int: Int
+ init(system: ActorSystem) {
+ self.actorSystem = system
+ // << self.id = system.assignID(Self.self)
+ // MARK INITMAP[id] = INITIALIZED
+
+ var loops = 10
+ while loops > 0 {
+ self.int = loops
+ // MARK INITMAP[int] = INITIALIZED
+ // INITMAP: FULLY INITIALIZED
+ //
+ // IF INITMAP[IMPLICIT_HOP_TO_SELF] != DONE {
+ // <<
+ // MARK INITMAP[IMPLICIT_HOP_TO_SELF] = DONE
+ // }
+ //
+ // IF INITMAP[ACTOR_READY] != INITIALIZED {
+ // << system.actorReady(self)
+ // MARK INITMAP[ACTOR_READY] = INITIALIZED
+ // }
+ escape(self)
+
+ loops -= 1
+ }
+ }
+}
+```
+
+Using this technique we are able to emit the ready call only once, and put off the complexity of dealing with repeated ready calls from distributed actor system library authors.
+
+> The same technique is used to avoid hopping to the self executor 10 times, and the implicit hop-to-self is only performed once, on the initial iteration where the actor became fully initialized.
+
+Things get more complex in the face of failable as well as throwing initializers. Specifically, because we not only have to assign identities, we also need to ensure that they are resigned when the distributed actor is deallocated. In the simple, non-throwing initialization case this is simply done in the distributed actor's `deinit`. However, some initialization semantics make this more complicated.
+
+### Resigning distributed actor IDs
+
+In addition to assigning `ID` instances to specific actors as they get created, we must also *always* ensure the `ID`s assigned are resigned as their owning actors get destroyed.
+
+Resigning an `ID` allows the actor system to release any resources it might have held in association with this actor. Most often this means removing it from some internal lookup table that was used to implement the `resolve(ID) -> Self` method of a distributed actor, but it could also imply tearing down connections, clearing caches, or even dropping any in-flight messages addressed to the now terminated actor.
+
+In the simple case this is trivially solved by deinitialization: we completely initialize the actor, and once it deinitializes, we invoke `resignID` in the actor's deinitializer:
+
+```swift
+deinit {
+ // << self.actorSystem.resignID(self.id)
+}
+```
+
+This also works with user defined deinitializers, where the resign call is injected as the *first* operation in the deinitializer:
+
+```swift
+// user-defined deinit
+deinit {
+ // << self.actorSystem.resignID(self.id)
+ print("deinit \(self.id)")
+}
+```
+
+Things get more complicated once we take into account the existence of *failable* and *throwing* initializers. Existing Swift semantics around those types of initializers, and their effect on if and when `deinit` is invoked mean that we need to take special care of them.
+
+Let us first discuss [failable initializers](https://docs.swift.org/swift-book/LanguageGuide/Initialization.html#ID224), i.e. initializers which are allowed to assign `nil` during their initialization. As actors allow such initializers, distributed actors should too, in order to make the friction of moving from local-only to distributed actors as small as possible.
+
+```swift
+distributed actor DA {
+ var int: Int
+
+ init?(int: Int, system: ActorSystem) {
+ self.actorSystem = system
+ // << self.id = actorSystem.assignID(Self.self)
+ // ...
+ if int < 10 {
+ // ...
+ // << self.actorSystem.resignID(self.id)
+ return nil
+ }
+ self.int = int
+ // << self.actorSystem.actorReady(self)
+ }
+
+ // deinit {
+ // << self.actorSystem.resignID(self.id)
+ // }
+}
+```
+
+Due to rules about actor and class init/deinit, when we `return nil` from a failable initializer, its deinitializer *does not run* (!). Because of this, we cannot rely on the deinit to resign the ID as we'd leave an un-used, but still registered identity hanging in the actor system, and the `resignID` is injected just before the "failing return" from such an initializer. This is done transparently, and neither distributed actor developers nor actor system developers need to worry about this: the ID is always resigned properly.
+
+> This does mean that `resignID` may be called without `actorReady` having ever been called! The system should react to this as it would to any usual resignID and free any resources associated with the identifier.
+
+Next, we need to discuss *throwing* initializers, and their multiple paths of execution. Again, rules about class and actor deinitialization, are tightly related to whether a type's `deinit` will be executed or not, so let us analyze the following example:
+
+```swift
+distributed actor DA {
+ var int: Int
+
+ init(int: Int, system: ActorSystem) throws {
+ self.actorSystem = system
+ // << self.id = system.assignID(Self.self)
+ // ...
+ if int <= 1 {
+ // ...
+ // << self.actorSystem.resignID(self.id)
+ throw Boom() // [1]
+ }
+
+ if int <= 2 {
+ self.int = int
+ // ~ become fully initialized ~
+ throw Boom() // [2]
+ }
+
+ throw Boom() // Boom for good measure... (same as [2] though)
+ // theoretically, the ready call is inserted at the end of the init:
+ // << system.actorReady(self)
+ }
+
+ init(int: Int, system: ActorSystem) async throws {
+ // << self.id = system.assignID(Self.self)
+ // ...
+ if int <= 1 {
+ // ...
+ // << self.actorSystem.resignID(self.id)
+ throw Boom() // [1]
+ }
+
+ if int <= 2 {
+ self.int = int
+ // ~ become fully initialized ~
+ // << system.actorReady(self)
+ throw Boom() // [2]
+ }
+
+ throw Boom() // Boom for good measure... (same as [2] though)
+ }
+
+ // deinit {
+ // << self.actorSystem.resignID(self.id)
+ // }
+}
+```
+
+The actor shown above both has state that it needs to initialize, and it is going to throw. It will throw either before becoming fully initialized `[1]`, or after it has initialized all of its stored properties `[2]`. Swift handles those two executions differently. Only a fully initialized reference type's `deinit` is going to be executed. This means that if the `init` throws at `[1]` we need to inject a `resignID` call there, while if it throws after becoming fully initialized, e.g. on line `[2]` we do not need to inject the `resignID` call, because the actor's `deinit` along with the injected-there `resignID` will be executed instead.
+
+Both the synchronous and asynchronous initializers deal with this situation well, because the resign call must be paired with the assign, and if the actor was called ready before it calls `resignID` it does not really impact the resignation logic.
+
+To summarize, the following are rules that distributed actor system implementors can rely on:
+
+- `assignID(_:)` will be called exactly-once, at the very beginning of the initialization of a distributed actor associated with the system.
+- `actorReady(_:)` will be called exactly-once, after all other properties of the distributed actor have been initialized, and it is ready to receive messages from other peers. By construction, it will also always be called after `assignID(_:)`.
+- `resignID(_:)` will be called exactly-once as the actor becomes deinitialized, or fails to finish its initialization. This call will always be made after an `assignID(_:)` call. While there may be ongoing racy calls to the transport as the actor invokes this method, any such calls after `resignID(_:)` was invoked should be handled as if actor never existed to begin with.
+
+Note that the system usually should not hold the actor with a strong reference, as doing so inhibits its ability to deinit until the system lets go of it.
+
+### Resolving distributed actors
+
+Every distributed actor type has a static "resolve" method with the following signature:
+
+```swift
+extension DistributedActor {
+ public static func resolve(id: Self.ID, using system: Self.ActorSystem) throws -> Self {
+ ...
+ }
+}
+```
+
+This method will return a distributed actor reference, or throw when the actor system is unable to resolve the reference.
+
+The `resolve(id:using:)` method on distributed actors is an interesting case of the Swift runtime collaborating with the `DistributedActorSystem`. The Swift runtime implements this method as calling the passed-in actor system to resolve the ID, and if the system claims that this is a _remote_ reference, the Swift runtime will allocate a _remote_ distributed actor reference, sometimes called a "proxy" instance.
+
+Its implementation can be thought of as follows:
+
+```swift
+extension DistributedActor {
+ // simplified implementation
+ static func resolve(id: Self.ID, using system: ActorSystem) throws -> Self {
+ switch try system.resolve(id: id, as: Self.self) {
+ case .some(let localInstance):
+ return localInstance
+ case nil:
+ return <>(id: id, system: system)
+ }
+ }
+}
+```
+
+Specifically, this calls into the `ActorSystem`'s `resolve(id:as:)` method which has a slightly different signature than the one defined on actors, specifically it can return `nil` to signal the instance is not found in this actor system, but we're able to proxy it.
+
+> The **result** of `resolve(id:using:)` may be a **local instance** of a distributed actor, or a **reference to a remote** distributed actor.
+
+The resolve implementation should be fast, and should be non-blocking. Specifically, it should *not* attempt to contact the remote peer to confirm whether this actor really exists or not. Systems should blindly resolve remote identifiers assuming the remote peer will be able to handle them. Some systems may after all spin up actor instances lazily, upon the first message sent to them etc.
+
+Allocating the remote reference is implemented by the Swift runtime, by creating a fixed-size object that serves only the purpose of proxying calls into the `system.remoteCall`. The `_isDistributedRemoteActor()` function always returns `true` for such a reference.
+
+If the system entirely fails to resolve the ID, e.g. because it was ill-formed or the system is unable to handle proxies for the given ID, it must throw with an error conforming to `DistribtuedActorSystemError`, rather than returning `nil`. An example implementation could look something like this:
+
+```swift
+final class ClusterSystem: DistributedActorSystem {
+ private let lock: Lock
+ private var localActors: [ActorID: AnyWeaklyHeldDistributedActor] // stored into during actorReady
+
+ // example implementation; more sophisticated ones can exist, but boil down to the same idea
+ func resolve(id: ID, as actorType: Actor.Type)
+ throws -> Actor? where Actor: DistributedActor,
+ Actor.ID == Self.ActorID,
+ Actor.SerializationRequirement == Self.SerializationRequirement {
+ if validate(id) == .illegal {
+ throw IllegalActorIDError(id)
+ }
+
+ return lock.synchronized {
+ guard let known = self.localActors[id] else {
+ return nil // not local actor, but we can allocate a remote reference for it
+ }
+
+ return try known.as(Actor.self) // known managed local instance
+ }
+ }
+}
+```
+
+The types work out correctly since it is the specific actor system that has _assigned_ the `ID`, and stored the specific distributed actor instance for the specific `ID`.
+
+> **Note:** Errors thrown by actor systems should conform to the `protocol DistributedActorSystemError: Error {}` protocol. While it is just a marker protocol, it helps end users understand where an error originated.
+
+Attempting to ready using one type, and resolve using another will cause a throw to happen during the resolve, e.g. like this:
+
+```swift
+distributed actor One {}
+distributed actor Two {}
+
+let one = One(system: cluster)
+try Two.resolve(id: one.id, using: cluster)
+// throws: DistributedActorResolveError.wrongType(found: One) // system specific error
+```
+
+This is only the case for local instances, though. For remote instances, by design, the local actor system does not track any information about them and as any remote call can fail anyway, the failures surface at call-site (as the remote recipient will fail to be resolved).
+
+### Invoking distributed methods
+
+Invoking a distributed method (or distributed computed property) involves a number of steps that occur on two "sides" of the call.
+
+The local/remote wording which works well with actors in general can get slightly confusing here, because every call made "locally" on a "remote reference", actually results in a "local" invocation execution on the "remote system". Instead, we will be using the terms "**sender**" and "**recipient**" to better explain which side of a distributed call we are focusing on.
+
+As was shown earlier, invoking a `distributed func` essentially can follow one of two execution paths:
+
+- if the distributed actor instance was **local**:
+ - the call is made directly, as if it was a plain-old local-only `actor`
+- if the distributed actor was **remote**:
+ - the call must be transformed into an invocation that will be offered to the `system.remoteCall(...)` method to execute
+
+The first case is governed by normal actor execution rules. There might be a context switch onto the actor's executor, and the actor will receive and execute the method call as usual.
+
+In this section, we will explain all the steps involved in the second, remote, case of a distributed method call. The invocations will be using two very important types that represent the encoding and decoding side of such distributed method invocations.
+
+The full listing of those types is presented below:
+
+```swift
+protocol DistributedActorSystem: ... {
+ // ...
+ associatedtype InvocationEncoder: DistributedTargetInvocationEncoder
+ associatedtype InvocationDecoder: DistributedTargetInvocationDecoder
+
+ func makeInvocationEncoder() -> InvocationEncoder
+}
+```
+
+
+
+```swift
+public protocol DistributedTargetInvocationEncoder {
+ associatedtype SerializationRequirement
+
+ /// Record a type of generic substitution which is necessary to invoke a generic distributed invocation target.
+ ///
+ /// The arguments must be encoded order-preserving, and once `decodeGenericSubstitutions`
+ /// is called, the substitutions must be returned in the same order in which they were recorded.
+ mutating func recordGenericSubstitution(_ type: T.Type) throws
+
+ /// Record an argument of `Argument` type in this arguments storage.
+ ///
+ /// The argument name is provided to the `name` argument and can either be stored or ignored.
+ /// The value of the argument is passed as the `argument`.
+ ///
+ /// Ad-hoc protocol requirement.
+ mutating func recordArgument(
+ _ argument: RemoteCallArgument
+ ) throws
+
+ /// Record the error type thrown by the distributed invocation target.
+ /// If the target does not throw, this method will not be called and the error type can be assumed `Never`.
+ mutating func recordErrorType(_ type: E.Type) throws
+
+ /// Record the return type of the distributed method.
+ /// If the target does not return any specific value, this method will not be called and the return type can be assumed `Void`.
+ ///
+ /// Ad-hoc protocol requirement.
+ mutating func recordReturnType(_ type: R.Type) throws
+
+ /// All values and types have been recorded.
+ /// Optionally "finalize" the recording, if necessary.
+ mutating func doneRecording() throws
+}
+
+/// Represents an argument passed to a distributed call target.
+public struct RemoteCallArgument {
+ /// The "argument label" of the argument.
+ /// The label is the name visible name used in external calls made to this
+ /// target, e.g. for `func hello(label name: String)` it is `label`.
+ ///
+ /// If no label is specified (i.e. `func hi(name: String)`), the `label`,
+ /// value is empty, however `effectiveLabel` is equal to the `name`.
+ ///
+ /// In most situations, using `effectiveLabel` is more useful to identify
+ /// the user-visible name of this argument.
+ let label: String?
+ var effectiveLabel: String {
+ return label ?? name
+ }
+
+ /// The internal name of parameter this argument is accessible as in the
+ /// function body. It is not part of the functions API and may change without
+ /// breaking the target identifier.
+ ///
+ /// If the method did not declare an explicit `label`, it is used as the
+ /// `effectiveLabel`.
+ let name: String
+
+ /// The value of the argument being passed to the call.
+ /// As `RemoteCallArgument` is always used in conjunction with
+ /// `recordArgument` and populated by the compiler, this Value will generally
+ /// conform to a distributed actor system's `SerializationRequirement`.
+ let value: Value
+}
+```
+
+
+
+```swift
+public protocol DistributedTargetInvocationDecoder {
+ associatedtype SerializationRequirement
+
+ mutating func decodeGenericSubstitutions() throws -> [Any.Type]
+
+ /// Attempt to decode the next argument from the underlying buffers into pre-allocated storage
+ /// pointed at by 'pointer'.
+ ///
+ /// This method should throw if it has no more arguments available, if decoding the argument failed,
+ /// or, optionally, if the argument type we're trying to decode does not match the stored type.
+ ///
+ /// Ad-hoc protocol requirement.
+ mutating func decodeNextArgument() throws -> Argument
+
+ mutating func decodeErrorType() throws -> Any.Type?
+
+ mutating func decodeReturnType() throws -> Any.Type?
+}
+```
+
+#### Sender: Invoking a distributed method
+
+A call to a distributed method (or computed property) on a remote distributed actor reference needs to be turned into a runtime introspectable representation which will be passed to the `remoteCall` method of a specific distributed actor system implementation.
+
+In this section, we'll see what happens for the following `greet(name:)` distributed method call:
+
+```swift
+// distributed func greet(name: String) -> String { ... }
+
+try await greeter.greet(name: "Alice")
+```
+
+Such invocation is calling the method via a "distributed thunk" rather than directly. The "distributed thunk" is synthesized by the compiler for every `distributed func`, and can be illustrated by the following snippet:
+
+```swift
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SYNTHESIZED ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+extension Greeter {
+ // synthesized; not user-accessible thunk for: greet(name: String) -> String
+ nonisolated func greet_$distributedThunk(name: String) async throws -> String {
+ guard _isDistributedRemoteActor(self) else {
+ // the local func was not throwing, but since we're nonisolated in the thunk,
+ // we must hop to the target actor here, meaning the 'await' is always necessary.
+ return await self.greet(name: name)
+ }
+
+ // [1] prepare the invocation object:
+ var invocation = self.actorSystem.makeInvocationEncoder()
+
+ // [1.1] if method has generic parameters, record substitutions
+ // e.g. for func generic(a: A, b: B) we would get two substitutions,
+ // for the generic parameters A and B:
+ //
+ // << invocation.recordGenericSubstitution()
+ // << invocation.recordGenericSubstitution()
+
+ // [1.2] for each argument, synthesize a specialized recordArgument call:
+ try invocation.recordArgument(RemoteCallArgument(label: nil, name: "name", value: name))
+
+ // [1.3] if the target was throwing, record Error.self,
+ // otherwise do not invoke recordErrorType at all.
+ //
+ // << try invocation.recordErrorType(Error.self)
+
+ // [1.4] we also record the return type; it may or may not be necessary to
+ // transmit over the wire but if necessary, the system may choose to do so.
+ //
+ // This call is not made when the return type is Void.
+ try invocation.recordReturnType(String.self)
+
+ // [1.5] done recording arguments
+ try invocation.doneRecording()
+
+ // [2] invoke the `remoteCall` method of the actor system
+ return try await self.actorSystem.remoteCall(
+ on: self,
+ target: RemoteCallTarget(...),
+ invocation: invocation,
+ throwing: Never.self, // the target func was not throwing
+ returning: String.self
+ )
+ }
+}
+```
+
+The synthesized thunk is always throwing and asynchronous. This is correct because it is only invoked in situations where we might end up calling the `actorSystem.remoteCall(...)` method, which by necessity is asynchronous and throwing.
+
+The thunk is `nonisolated` because it is a method that can actually run on a *remote* instance, and as such is not allowed to touch any other state than other nonisolated stored properties. This is specifically designed such that the thunk and actor system are able to access the `id` of the actor (and the `actorSystem` property itself) which is necessary to perform the actual remote message send.
+
+The `nonisolated` aspect of the method has another important role to play: if this invocation happens to be on a local distributed actor, we do not want to "hop" executors twice. If this invocation were on a local actor, only accessing `nonisolated` state, or for other reasons the hop could be optimized away, we want to keep this ability for the optimizer to do as good of a job as it would for local only actors. If the instance was remote, we don't need to suspend early at all, and we leave it to the `ActorSystem` to decide when exactly the task will suspend. For example, the system may only suspend the call after it has sent the bytes synchronously over some IPC channel, etc. The semantics of to suspend are highly dependent on the specific underlying transport, and thanks to this approach we allow system implementations to do the right thing, whatever that might be: they can suspend early, late, or even not at all if the call is known to be impossible to succeed.
+
+Note that the compiler will pass the `self` of the distributed *known-to-be-remote* actor to the `remoteCall` method on the actor system. This allows the system to check the passed type for any potential, future, customization points that the actor may declare as static properties, and/or conformances affecting how a message shall be serialized or delivered. It is impossible for the system to access any of that actor's state, because it is remote after all. The one piece of state it will need to access though is the actor's `id` because that is signifying the *recipient* of the call.
+
+The thunk creates the `invocation` container `[1]` into which it records all arguments. Note that all these APIs are using only concrete types, so we never pay for any existential wrapping or other indirections. Arguments are wrapped in a `RemoteCallArgument` which also provides additional information about the argument, such as the labels used in its declaration. This can be useful for transports which wish to encode values in named dictionaries, e.g. such as JSON dictionaries. It is important to recognize that storing names or labels is _not_ required or recommended for the majority of transports, however for those which need it, they are free to use this additional information.
+
+Since the strings created are string literals, known at compile time, there is no allocation impact for this argument wrapper type and this additional label information.
+
+> It may seem tempting to simply record arguments into a dictionary using their effective labels, however this can lead to issues due to labels being allowed to be reused. For example, `func sum(a a1: Int, a a2: Int)` is a legal, although not very readable, function declaration. A naive encoding scheme could risk overriding the "first `a`" value with the "second `a` if it strongly relied on the labels only. A distributed actor system implementation should decide how to deal with such situations and may choose to throw at runtime if such a risky signature is detected, or apply some mangling, e.g. use the parameter names to clarify which value was encoded.
+
+The `record...` calls are expected to serialize the values, using any mechanism they want to, and thanks to the fact that the type performing the recording is being provided by the specific `ActorSystem`, it also knows that it can rely on the arguments to conform to the system's `SerializationRequirement`.
+
+The first step in the thunk is to record any "generic substitutions" `[1.1]` if they are necessary. This makes it possible for remote calls to support generic arguments, and even generic distributed actors. The substitutions are not recorded for call where the generic context is not necessary for the invocation. For a generic method, however, the runtime will invoke the `recordGenericTypeSubstitution` with _concrete_ generic arguments that are necessary to perform the call. For example, if we declared a generic `echo` method like this:
+
+```swift
+distributed func echo(_ value: T) -> T
+```
+
+and call it like this:
+
+```swift
+try await greeter.echo("Echo!") // typechecks ok; String: SerializationRequirement
+```
+
+The Swift runtime would generate the following call:
+
+```swift
+try invocation.recordGenericTypeSubstitution(String.self)
+```
+
+This method is implemented by a distributed actor system library, and can use this information to double-check this type against an allow-list of types allowed to be transmitted over the wire, and then store and send it over to the recipient such that it knows what type to decode the argument as.
+
+Next, the runtime will record all arguments of the invocation `[1.2]`. This is done in a series of `recordArgument` calls. If the type of actor the target is declared on also includes a generic parameter that is used by the invocation, this also is recorded.
+
+As the `recordArgument(_:)` method is generic over the argument type (``), and requires the argument to conform to `SerializationRequirement` (which in turn was enforced at compile time by [SE-0336][isolation]), the actor system implementation will have an easy time to serialize or validate this argument. For example, if the `SerializationRequirement` was codable — this is where one could invoke `SomeEncoder().encode(argument)` because `Argument` is a concrete type conforming to `Codable`!
+
+Finally, the specific error `[1.3]` and return types `[1.4]` are also recorded. If the function is not throwing, `recordErrorType` is not called. Likewise, if the return type is `Void` the `recordReturnType` is not called.
+
+Recording the error type is mostly future-proofing and currently will only ever be invoked with the `Error.self` or not at all. It allows informing the system if a throw from the remote side is to be expected, and technically, if Swift were to gain typed throws this method could record specific expected error types as well — although we have no plans with regards to typed throws at this point in time.
+
+The last encoder call `doneRecording()` is made, to signal to the invocation encoder that no further record calls will be made. This is useful since with the optional nature of some of the calls, it would be difficult to know for a system implementation when the invocation is fully constructed. Operations which may want to be delayed until completion could include serialization, de-duplicating values or similar operations which benefit from seeing the whole constructed invocation state in the encoder.
+
+Lastly, the populated encoder, along with additional type and function identifying information is passed to the `remoteCall`, or `remoteCallVoid` method on the actor system which should actually perform the message request/response interaction with the remote actor.
+
+#### Sender: Serializing and sending invocations
+
+The next step in making a remote call is serializing a representation of the distributed method (or computed property) invocation. This is done through a series of compiler, runtime, and distributed actor system interactions. These interactions are designed to be highly efficient and customizable. Thanks to the `DistributedTargetInvocationEncoder`, we are able to never resort to existential boxing of values, allow serializers to manage and directly write into their destination buffers (i.e. allowing for zero copies to be performed between the message serialization and the underlying networking layer), and more.
+
+Let us consider a `ClusterSystem` that will use `Codable` and send messages over the network. Most systems will need to form some kind of "Envelope" (easy to remember as: "the thing that contains the **message** and also has knowledge of the **recipient**"). For the purpose of this proposal, we'll define a a `WireEnvelope` and use it in the next snippets to showcase how a typical actor system would work with it. This type is not pre-defined or required by this proposal, but it is something implementations will frequently do on their own:
+
+```swift
+// !! ClusterSystem or WireEnvelope are NOT part of the proposal, but serves as illustration how actor systems might !!
+// !! implement the necessary pieces of the DistributedActorSystem protocol. !!
+
+final struct ClusterSystem: DistributedActorSystem {
+ // ...
+ typealias SerializationRequirement = Codable
+ typealias InvocationEncoder = ClusterTargetInvocationEncoder
+ typealias InvocationDecoder = ClusterTargetInvocationDecoder
+
+ // Just an example, we can implement this more efficiently if we wanted to.
+ private struct WireEnvelope: Codable, Sendable {
+ var recipientID: ClusterSystem.ActorID // is Codable
+
+ /// Mangled method/property identifier, e.g. in a mangled format
+ var identifier: String
+
+ // Type substitutions matter only for distributed methods which use generics:
+ var genericSubstitutions: [String]
+
+ // For illustration purposes and simplicity of code snippets we use `[Data]` here,
+ // but real implementations can be much more efficient here — packing all the data into exact
+ // byte buffer that will be passed to the networking layer, etc.
+ var arguments: [Data] // example is using Data, because that's what Codable coders use
+
+ // Metadata can be used by swift-distributed-tracing, or other instrumentations to carry extra information:
+ var metadata: [String: [Data]] // additional metadata, such as trace-ids
+ }
+}
+```
+
+Note that `method` property is enough to identify the target of the call, we do not need to carry any extra type information explicitly in the call. The method identifier is sufficient to resolve the target method on the recipient, however in order to support generic distributed methods, we need to carry additional (mangled) type information for any of the generic parameters of this specific method invocation. Thankfully, these are readily provided to us by the Swift runtime, so we'll only need to store and send them over.
+
+> **Note:** An implementation may choose to define any shape of "envelope" (or none at all) that suits its needs. It may choose to transport mangled names of involved types for validation purposes, or choose to not transfer them at all and impose other limitations on the system and its users for the sake of efficiency.
+>
+> While advanced implementations may apply compression and other techniques to minimize the overhead of these envelopes — this is a deep topic by itself, and we won't be going in depth on it in this proposal — rest assured though, we have focused on making different kinds of implementations possible with this approach.
+
+Next, we will discuss how the `InvocationEncoder` can be implemented in order to create such `WireEnvelope`.
+
+> Note on ad-hoc requirements: Some of the protocol requirements on the encoder, as well as actor system protocols, are so-called "ad-hoc" requirements. This means that they are not directly expressed in Swift source, but instead the compiler is aware of the signatures and specifically enforces that a type conforming to such protocol implements these special methods.
+>
+> Specifically, methods which fall into this category are functions which use the `SerializationRequirement` as generic type requirement. This is currently not expressible in plain Swift, due to limitations in the type system which are difficult to resolve immediately, but in time as this could become implementable these requirements could become normal protocol requirements.
+>
+> This tradeoff was discussed at length and we believe it is worth taking, because it allows us to avoid numerous un-necessary type-casts, both inside the runtime and actor system implementations. It also allows us to avoid any existential boxing and thus lessens the allocation footprint of making remote calls which is an important aspect of the design and use cases we are targeting.
+
+The following listing illustrates how one _could_ implement a `DistributedTargetInvocationEncoder`:
+
+```swift
+extension ClusterSystem {
+ typealias InvocationEncoder = ClusterTargetInvocationEncoder
+
+ func makeInvocationEncoder() -> Self.InvocationEncoder {
+ return ClusterTargetInvocation(system: system)
+ }
+}
+
+struct ClusterTargetInvocationEncoder: DistributedTargetInvocationEncoder {
+ typealias SerializationRequirement = ClusterSystem.SerializationRequirement
+
+ let system: ClusterSystem
+ var envelope: Envelope
+
+ init(system: ClusterSystem) {
+ self.system = system
+ self.envelope = .init() // new "empty" envelope
+ }
+
+ /// The arguments must be encoded order-preserving, and once `decodeGenericSubstitutions`
+ /// is called, the substitutions must be returned in the same order in which they were recorded.
+ mutating func recordGenericSubstitution(_ type: T.Type) throws {
+ // NOTE: we are showcasing a pretty simple implementation here...
+ // advanced systems could use mangled type names or registered type IDs.
+ envelope.genericSubstitutions.append(String(reflecting: T.self))
+ }
+
+ mutating func recordArgument(_ argument: RemoteCallArgument) throws {
+ // in this implementation, we just encode the values one-by-one as we receive them:
+ let argData = try system.encoder.encode(argument) // using whichever Encoder the system has configured
+ envelope.arguments.append(argData)
+ }
+
+ mutating func recordErrorType(_ errorType: E.Type) throws {
+ envelope.errorType = String(reflecting: errorType)
+ }
+
+ mutating func recordReturnType(_ returnType: R.Type) throws {
+ envelope.returnType = String(reflecting: returnType)
+ }
+
+ /// Invoked when all the `record...` calls have been completed and the `DistributedTargetInvocation`
+ /// will be passed off to the `remoteCall` to perform the remote call using this invocation representation.
+ mutating func doneRecording() throws {
+ // our impl does not need to do anything here
+ }
+}
+```
+
+The above encoder is going to be called by the Swift runtime as was explained in the previous section.
+
+Once that is complete, the runtime will pass the constructed `InvocationEncoder` to the `remoteCall`:
+
+```swift
+ extension ClusterSystem {
+ // 'remoteCall' is not a protocol requirement, however its signature is well known to the compiler,
+ // and it will invoke the method. We also are guaranteed that the 'Success: Codable' requirement is correct,
+ // since the type-system will enforce this conformance thanks to the type-level checks on distributed funcs.
+ func remoteCall(
+ on actor: Actor,
+ target: RemoteCallTarget,
+ invocation: Self.InvocationEncoder,
+ throwing: Failure.Type,
+ returning: Success.Type
+ ) async throws -> Success
+ where Actor: DistributedActor,
+ Actor.ID == ActorID.
+ Failure: Error,
+ Success: Self.SerializationRequirement {
+ var envelope = invocation.envelope
+
+ // [1] the recipient is transferred over the wire as its id
+ envelope.recipient = recipient.id
+
+ // [2] the method is a mangled identifier of the 'distributed func' (or var).
+ // In this system, we just use the mangled name, but we could do much better in the future.
+ envelope.target = target.identifier
+
+ // [3] send the envelope over the wire and await the reply:
+ let responseData = try await self.underlyingTransport.send(envelope, to: actor.id)
+
+ // [4] decode the response from the response bytes
+ // in our example system, we're using Codable as SerializationRequirement,
+ // so we can decode the response like this (and never need to cast `as? Codable` etc.):
+ return try self.someDecoder.decode(as: Success.self, from: responseData)
+ }
+}
+```
+
+The overall purpose of this `remoteCall` implementation is to create some form of message representation of the invocation and send it off to the remote node (or process) to receive and invoke the target method on the remote actor.
+
+In our example implementation, the `Invocation` already serialized the arguments and stored them in the `Envelope`, so the `remoteCall` only needs to add the information about the call recipient `[1]`, and the target (method or computed property) of the call `[2]`. In our example implementation, we just store the target's mangled name `[2]`, which is simple, but it has its challenges in regard to protocol evolution.
+
+One notable issue that mangled names have is that any change in the method signature will result in not being able to resolve the target method anymore. We are very much aware of the issues this may cause to protocol evolution, and we lay out plans in [Future Work](#future-work) to improve the lookup mechanisms in ways that will even allow adding parameters (with default values), in wire (and ABI) compatible ways.
+
+The final step is handing over the envelope containing the encoded arguments, recipient information, etc., to the underlying transport mechanism `[3]`. The transport does not really have to concern itself with any of the specifics of the call, other than transmitting the bytes to the callee and the response data back. As we get the response data back, we have the concrete type of the expected response and can attempt to decode it `[4]`.
+
+> Note on `remoteCallVoid`: One limitation in the current implementation approach is that a remote call signature cannot handle void returning methods, because of the `Success: SerializationRequirement` requirement on the method.
+>
+> This will be possible to solve using the incoming [Variadic Generics](https://forums.swift.org/t/variadic-generics/54511) language feature that is being currently worked on and pitched. With this feature, the return type could be represented as variadic generic and the `Void` return type would be modeled as "empty" tuple, whereas a value return would contain the specific type of the return, this way we would not violate the `Success: SerializationRequirement` when we needed to model `Void` calls.
+
+#### Recipient: Receiving invocations
+
+On the remote side, there usually will be some receive loop or similar mechanism that is implemented in the transport layer of the actor system. In practice this often means binding a port and receiving TCP (or UDP) packets, applying some form of framing and eventually decoding the incoming message envelope.
+
+Since the communication of the sending and receiving side is going to be implemented by the same type of transport and actor system, receiving the envelopes is straightforward: we know the wire protocol, and follow it to receive enough bytes to decode the `Envelope` which we sent a few sections above.
+
+This part does not have anything specific prescribed in the `DistributedActorSystem` protocol. It is up to every system to implement whichever transport mechanism works for it. While not a "real" snippet, this can be thought of a simple loop over incoming connections, like this:
+
+```swift
+// simplified pseudo code for illustration purposes
+func receiveLoop(with node: Node) async throws {
+ for try await envelopeData in connection(node).receiveEnvelope {
+ await self.receive(envelopeData)
+ }
+}
+```
+
+In a real server implementation we'd likely use a [Swift NIO](https://github.com/apple/swift-nio) `ChannelPipeline` to perform this networking, framing and emitting of `Envelope`s, but this is beyond the scope of what we need to explain in this proposal to get the general idea of how this is going to work.
+
+#### Recipient: Deserializing incoming invocations
+
+Now that we have received all the bytes for one specific envelope, we need to perform a two-step deserialization on it.
+
+First, we'll need to decode the target identifier (e.g. method name, mangled method name, or some other form of target identifier), and the actor `ID` of the recipient. These are necessary to decode always, as we need to locate both the method and actor we're trying to invoke.
+
+Next, the deserialization of the actual message representation of our invocation will take place. However, this is done lazily. Rather than just decoding the values and storing them somewhere in our system implementation, these will be requested by the Swift runtime when it is about to perform the method call.
+
+Before we dive deeper into this, let us visualize how this two-step process is intended to work, by looking at what might be a typical envelope format on the wire:
+
+```c
++------------------------------- ENVELOPE --------------------------------------+
+| +---------- HEADER --------++-------------------- MESSAGE ------------------+ |
+| | target | recipient | ... || [ ... lazy decoded section: types, args ... ] | |
+| +--------------------------++-----------------------------------------------+ |
++-------------------------------------------------------------------------------+
+```
+
+We see that as we decode our wire envelope, we are able to get the header section, and all values contained within it eagerly and leave the remaining slice of the buffer untouched. It will be consumed during performing of the invocation soon enough. The nice thing about this design is that we're still able to hold onto the actual buffer handed us from the networking library, and we never had to copy the buffer to our own local copies.
+
+Next, we need to prepare for the decoding of the message section. This is done by implementing the remaining protocol requirements on the `ClusterTargetInvocation` type we defined earlier, as well as implementing a decoding iterator of type `DistributedTargetInvocationArgumentDecoder`, as shown below:
+
+```swift
+struct ClusterTargetInvocationDecoder: DistributedTargetInvocationDecoder {
+ typealias SerializationRequirement = Codable
+
+ let system: ClusterSystem
+ var bytes: ByteBuffer
+
+ mutating func decodeGenericSubstitutions() throws -> [Any.Type] {
+ let subCount = try self.bytes.readInt()
+
+ var subTypes: [Any.Type] = []
+ for _ in 0..() throws -> Argument {
+ try nextDataLength = try bytes.readInt()
+ let nextData = try bytes.readData(bytes: nextDataLength)
+ // since we are guaranteed the values are Codable, so we can just invoke it:
+ return try system.decoder.decode(as: Argument.self, from: bytes)
+ }
+
+ mutating func decodeErrorType() throws -> Any.Type? {
+ let length = try self.bytes.readInt() // read the length of the type
+ guard length > 0 {
+ return nil // we don't always transmit it, 0 length means "none"
+ }
+ let typeName = try self.bytes.readString(length: length)
+ return try self.system.summonType(byName: typeName)
+ }
+
+ mutating func decodeReturnType() throws -> Any.Type? {
+ let length = try self.bytes.readInt() // read the length of the type
+ guard length > 0 {
+ return nil // we don't always transmit it, 0 length means "none"
+ }
+ let typeName = try self.bytes.readString(length: length)
+ return try self.system.summonType(byName: typeName)
+ }
+}
+```
+
+The general idea here is that the `InvocationDecoder` is *lazy* in its decoding and just stores the remaining bytes of the envelope. All we need to do for now is to implement the Invocation in such way that it expects the decoding methods be invoked in the following order (which is the same as the order on the sending side):
+
+- 0...1 invocation of `decodeGenericArguments`,
+- 0...n invocation(s) of `decoder.decodeNextArgument`,
+- 0...1 invocation of `decodeReturnType`,
+- 0...1 invocation of `decodeErrorType`.
+
+Decoding arguments is the most interesting here. This is another case where the compiler and Swift runtime enable us to implement things more easily. Since the `Argument` generic type of the `decodeNextArgument` is ensured to conform to the `SerializationRequirement`, actor system implementations can rely on this fact and have a simpler time implementing the decoding steps. For example, with `Codable` the decoding steps becomes a rather simple task of invoking the usual `Decoder` APIs.
+
+This decoder must be prepared by the actor system and eventually passed to the `executeDistributedTarget` method which we'll discuss next. That, Swift runtime provided, function is the one which will be calling the `decode...` methods and will is able to ensure all the type requirements are actually met and form the correct generic method invocations.
+
+> **Note:** This proposal does not include an implementation for the mentioned `summonType(byName:)` function, it is just one way systems may choose to implement these functions. Possible implementations include: registering all "trusted" types, using mangled names, or something else entirely. This proposal has no opinion about how these types are recovered from the transmitted values.
+
+#### Recipient: Resolving the recipient actor instance
+
+Now that we have prepared our `InvocationDecoder` we are ready to make the next step, and resolve the recipient actor which the invocation shall be made on.
+
+We already discussed how resolving actors works in [Resolving distributed actors](#resolving-distributed-actors), however in this section we can tie it into the real process of invoking the target function as well.
+
+In the example we're following so far, the recipient resolution is simple because we have the recipient ID available in the `Envelope.recipientID`, so we only need to resolve that using the system that is receiving the message:
+
+```swift
+guard let actor: any DistributedActor = try self.knownActors[envelope.recipientID] else {
+ throw ClusterSystemError.unknownRecipient(envelope.recipientID)
+}
+```
+
+This logic is the same as the internal implementation of the `resolve(id:as:)` method only that we don't have a need to validate the specific type of the actor — this will be handled by the Swift runtime in `executeDistributedTarget`'s implementation the target of the call which we'll explain in the next section.
+
+#### Recipient: The `executeDistributedTarget` method
+
+Invoking a distributed method is a tricky task, and involves a lot of type demangling, opening existential types, forming specific generic invocations and tightly managing all of that in order to avoid un-necessary heap allocations to pass the decoded arguments to the target function, etc. After iterating over multiple designs, we decided to expose a single `DistributedActorSystem.executeDistributedTarget` entry point which efficiently performs all the above operations.
+
+Thanks to abstracting the decoding logic into the `DistributedTargetInvocationDecoder` type, all deserialization can be made directly from the buffers that were received from the underlying network transport. The `executeDistributedTarget` method has no opinion about what serialization mechanism is used either, and any mechanism — be it `Codable` or other external serialization systems — can be used, allowing distributed actor systems developers to implement whichever coding strategy they choose, potentially directly from the buffers obtained from the transport layer.
+
+The `executeDistributedTarget` method is defined as:
+
+```swift
+extension DistributedActorSystem {
+ /// Prepare and execute a call to the distributed function identified by the passed arguments,
+ /// on the passed `actor`, and collect its results using the `ResultHandler`.
+ ///
+ /// This method encapsulates multiple steps that are invoked in executing a distributed function,
+ /// into one very efficient implementation. The steps involved are:
+ ///
+ /// - looking up the distributed function based on its name;
+ /// - decoding, in an efficient manner, all arguments from the `Args` container into a well-typed representation;
+ /// - using that representation to perform the call on the target method.
+ ///
+ /// The reason for this API using a `ResultHandler` rather than returning values directly,
+ /// is that thanks to this approach it can avoid any existential boxing, and can serve the most
+ /// latency sensitive-use-cases.
+ func executeDistributedTarget(
+ on actor: Actor,
+ mangledName: String,
+ invocation: inout Self.InvocationDecoder,
+ handler: ResultHandler
+ ) async throws where Actor: DistributedActor,
+ Actor.ID == ActorID,
+ ResultHandler: DistributedTargetInvocationResultHandler {
+ // implemented by the _Distributed library
+ }
+}
+```
+
+This method encapsulates all the difficult and hard to implement pieces of the target invocation, and it accepts the base actor the call should be performed on, along with a `DistributedTargetInvocationResultHandler`.
+
+Rather than having the `executeDistributedTarget` method return an `Any` result, we use the result handler in order to efficiently, and type-safely provide the result value to the actor system library implementation. This technique is the same as we did with the `recordArgument` method before, and it allows us to provide the _specific_ type including its `SerializationRequirement` conformance making handling results much simpler, and without having to resort to any casts which can be unsafe if used wrongly, or have impact on runtime performance.
+
+The `DistributedTargetInvocationResultHandler` is defined as follows:
+
+```swift
+protocol DistributedTargetInvocationResultHandler {
+ associatedtype SerializationRequirement
+
+ func onReturn(value: Success) async throws
+ where Success: SerializationRequirement
+ func onThrow(error: Error) async throws
+ where Failure: Error
+}
+```
+
+In a way, the `onReturn`/`onThrow` methods can be thought of as the counterparts of the `recordArgument` calls on the sender side. We need to encode the result and send it _back_ to the sender after all. This is why providing the result value along with the appropriate SerializationRequirement conforming type is so important — it makes sending back the reply to a call, as simple as encoding the argument of the call.
+
+Errors must be handled by informing the sender about the failed call. This is in order to avoid senders waiting and waiting for a reply, and eventually triggering a timeout; rather, they should be informed as soon as possible that a call has failed. Treat an error the same way as you would a valid return in terms of sending the reply back. However, it is not required to actually send back the actual error, as it may not be safe, or a good idea from a security and information exposure perspective, to send back entire errors. Instead, systems are encouraged to send back a reasonable amount of information about a failure, and e.g. optionally, only if the thrown error type is `Codable` and allow-listed to be sent over the wire, transport it directly.
+
+#### Recipient: Executing the distributed target
+
+Now that we have completed all the above steps, all building up to actually invoking the target of a remote call: it is finally time to do so, by calling the `executeDistributedTarget` method:
+
+```swift
+// inside recipient actor system
+let envelope: IncomingEnvelope = // receive & decode ...
+let recipient: DistributedActor = // resolve ...
+
+let invocationDecoder = InvocationDecoder(system: self, bytes: envelope.bytes)
+
+try await executeDistributedTarget(
+ on: recipient, // target instance for the call
+ mangledName: envelope.targetName, // target func/var for the call
+ invocation: invocationDecoder // will be used to perform decoding arguments,
+ handler: ClusterTargetInvocationResultHandler(system, envelope) // handles replying to the caller (omitted in proposal)
+)
+```
+
+This call triggers all the decoding that we discussed earlier, and if any of the decoding, or distributed func/var resolution fails this call will throw. Otherwise, once all decoding has successfully been completed, the arguments are passed through the buffer to a distributed method accessor that actually performs the local method invocation. Once the method returns, its results are moved into the handler where the actor system takes over in order to send a reply to the remote caller — completing the remote call!
+
+Internally, the execute distributed thunk heavily relies on the lookup and code generated by the compiler for every `distributed func` which we refer to as **distributed method accessor thunk**. This thunk is able to decode incoming arguments using the `InvocationDecoder` and directly apply the target function, all while properly handling generics and other important aspects of function invocations. It is the distributed method accessor thunk that must be located using the "target identifier" when we handle an incoming the remote call, the thunk then calls the actual target function.
+
+For sake of completeness, the listing below shows the distributed method accessor thunk that is synthesized by the compiler. The thunk contains compiler synthesized logic specific to every distributed function to locate the target function, obtain the expected parameter types and use the passed in decoder to decode the arguments to finally pass them to the final function application.
+
+The thunk can be thought of in terms of this abstract example. However, it cannot be implemented like this because of various interactions with the generic system as well as how emissions (function calls) actually work. Distributed method accessor thunks are implemented directly in IR as it would not be possible to synthesize the necessary emissions in any higher level part of the compiler (!). Thankfully, the logic contained in those accessors is fairly straightforward and can be imagined as:
+
+```swift
+distributed actor DA {
+ func myCompute(_ i: Int, _ s: String, _ d: Double) async throws -> String {
+ "i:\(i), s:\(s), d:\(d)"
+ }
+}
+
+extension DA {
+ // Distributed accessor thunk" for 'myCompute(_:_:_:) -> String'
+ //
+ // PSEUDO CODE FOR ILLUSTRATION PURPOSES; NOT IMPLEMENTABLE IN PLAIN SWIFT;
+ // Implemented in directly in IR for expressibility reasons, and not user-accessible.
+ nonisolated func $distributedFuncAccessor_myCompute(
+ decoder: UnsafeMutableRawPointer,
+ argumentTypes: UnsafeRawPointer,
+ resultBuffer: UnsafeRawPointer,
+ genericSubstitutions: UnsafeRawPointer,
+ witnessTables: UnsafeRawPointer,
+ numWitnessTables: Int,
+ actorSelf: UnsafeRawPointer) async {
+
+ // - get generic signature of 'myCompute'
+ // - create storage 'args' for all the parameters; it will be used directly
+ // - for every argument, get the argumentType
+ // - invoke 'decoder.decodeArgument()'
+ // - store in 'args'
+ // - deal with the generic substitutions, witness tables and prepare the call
+ // invoke 'myCompute' with 'args', and the prepared 'result' and 'error' buffers
+ }
+}
+```
+
+As we can see, this thunk is "just" taking care of converting the heterogeneous parameters into the well typed counterparts, and finally performing a plain-old method invocation using those parameters. The actual code emission and handling of generics for all this to work is rather complex and can only be implemented in the IR layer of the compiler. The good part about it is that the compiler is able to prepare and emit good errors in case the types or witness tables seem to be mismatched with the target or other issues are found. Allocations are also kept to a minimum, as no intermediate allocations need to be made for the arguments and they are stored and directly emitted into the call emission of the target.
+
+The thunk again uses the indirect return, so we can avoid any kind of implicit existential boxing even on those layers. Errors are always returned indirectly, so we do not need to do it explicitly.
+
+#### Recipient: Collecting result/error from invocations
+
+Now that the distributed method has been invoked, it eventually returns or throws an error.
+
+Collecting the return (or error) value is also implemented using the `DistributedMethodInvocationHandler` we passed to the `executeDistributedTarget(...)` method. This is done for the same reason as parameters: we need a concrete type in order to efficiently pass the values to the actor system, so it can encode them without going through existential wrappers. As we cannot implement the `invoke()` method to be codable over the expected types — we don't know them until we've looked up the actual method we were about to invoke (and apply generic substitutions to them).
+
+The implementation could look as follows:
+
+```swift
+extension ExampleDistributedMethodInvocationHandler {
+ func onReturn(result: Success) throws {
+ do {
+ let replyData = system.encoder.encode(result)
+ self.reply(replyData)
+ } catch {
+ self.replyError("Failed to encode reply: \(type(of: error))")
+ }
+ }
+
+ func onError(error: Failure) {
+ guard Failure is Encodable else {
+ // best effort error reporting just sends back the type string
+ // we don't want to send back string representation since it could leak sensitive information
+ self.replyError("\(Failure.self)")
+ }
+
+ // ... if possible, `as?` cast to Encodable and return an actual error,
+ // but only if it is allow-listed, as we don't want to send arbitrary errors back.
+ }
+}
+```
+
+We omit the implementations of `replyError` and `reply` because they are more of the same patterns that we have already discussed here, and this is a proposal focused on illustrating the language feature, not a complete system implementation after all.
+
+The general pattern here is the same as with decoding parameters, however in the opposite direction.
+
+Once the `onError` or `onReturn` methods complete, the `executeDistributedTarget` method returns, and its caller knows the distributed request/response has completed – at least, as far as this peer is concerned. We omit the implementation of the `reply` and `replyError` methods that the actor system would implement here, because they are pretty much the same process as sending the request, except that the message must be sent as a response to a specific request, rather than target a specific actor and method. How this is achieved can differ wildly between transport implementations: some have built-in request/reply mechanisms, while others are uni-directional and rely on tagging replies with identifiers such as "this is a reply for request 123456".
+
+## Amendments
+
+### Initializers no longer need to accept a single DistributedActorSystem
+
+During this review, feedback was received and addressed with regards to the previous implementation limitation that user defined designated actor initializers must have always accepted a single `DistributedActorSystem` conforming parameter. This was defined in [SE-0336: Distributed Actor Isolation](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0336-distributed-actor-isolation.md).
+
+The limitation used to be that one had to accept such parameter or the system would fail to synthesize the initializer an offer a compile-time error:
+
+```swift
+// PREVIOUSLY, as defined by SE-0336
+init(x: String) {}
+// ❌ error: designated distributed actor initializer 'init(x:)' is missing required 'DistributedActorSystem' parameter
+
+init(system: AnyDistributedActorSystem) {}
+// ✅ used to be ok; though the "unused" parameter looks confusing and is actually necessary
+```
+
+This system argument, picked by type, would have been picked up by the compiler and used in synthesis of necessary calls during a distributed actor's initialization. This led to a weird "dangling" parameter that is not used by visible code, but is crucial for the correctness of the program.
+
+This implementation restriction is now lifted, and is rephrased as requiring an assignment to the `self.actorSystem` property in non-delegating initializers. This is in line with how normal Swift works, and can be explained to users more intuitively, because every `distributed actor` has a synthesized `let actorSystem: ActorSystem` property, it clearly must be initialized to something as implied by normal initializer rules.
+
+The checks therefore are now plain property assignment checks, and the compiler is able to pick up the assigned property and synthesize the necessary `assignID` and `actorReady` calls based on the property, e.g.:
+
+```swift
+distributed actor Example {
+ init(x: String) {
+ // ❌ error: property 'actorSystem' was not initialized
+ // more educational notes to be produced here (e.g. what type it expects etc)
+ }
+
+ init (x: String, cluster: ClusterSystem) {
+ self.actorSystem = cluster // ✅ ok
+ }
+}
+```
+
+This means that it is also possible to assign a "global" or static actor system, however it is **strongly discouraged** to do so because it hurts reusability and testability, e.g. by swapping a test instance of an actor system during unit tests.
+
+```swift
+// Possible, but considered an anti-pattern as it hurts testability of such actor
+// DON'T DO THIS.
+distributed actor NotGoodIdea {
+ init() {
+ self.actorSystem = SomeSystem.global // anti-pattern, always accept an actor system via initializer.
+ }
+}
+```
+
+## Future work
+
+### Variadic generics removing the need for `remoteCallVoid`
+
+Once [variadic generics](https://forums.swift.org/t/variadic-generics/54511/2) are fully implemented, we will be able to remove the limitation that we cannot express the `remoteCall<..., Success: SerializationRequirement>(..., returning returnType: Success.Type)` function for the `Void` type, since it cannot always conform to `SerializationRequirement`.
+
+With variadic generics, it would be natural to conform an "empty tuple" to the `SerializationRequirement` and we'd this way be able to implement only a single method (`remoteCall`) rather than having to provide an additional special case implementation for `Void` return types.
+
+### Identifying, evolving and versioning remote calls
+
+At present remote calls use an opaque string identifier (wrapped as `RemoteCallTarget`) to refer to, and invoke remote call targets. This identifier is populated by default using the mangled name of the distributed thunk of the target function.
+
+#### Default distributed call target identification scheme
+
+Distributed actor system implementations shall treat the identifier as opaque value that they shall ship from the sender to the recipient node, without worrying too much about their contents. The identification scheme though has a large and important impact on the versioning story of distributed calls, so in this section we'd like to discuss and outline the general plans we foresee here as we will introduce proper and more versioning friendly schemes in the future.
+
+Swift's default mangling scheme is used for distributed methods is problematic for API evolution, however, it is a great "default" to pick until we devise a different scheme in the future. The mangling scheme is a good default because:
+
+- it allows callers to use all of the richness of Swift's calling semantics, including:
+ - overloads by type (e.g. we can call `receive(_:Int)` as well as `receive(_:String)`) and invoke the correct target based on the type.
+- it allows us to evolve APIs manually by adding overloads, deprecate methods etc, and we will continue to work towards a feature rich versioning story while adopting limited use-cases where these limitations are not a problem.
+
+This is also avoids a well-known problem from objective-c, where selectors must not accidentally be the same, otherwise bad-things-happen™.
+
+One potential alternative would be to use the full names of methods, i.e. `hello(name:surname:)`, similar to objective-c selectors to identify methods. However, this means the loss of any and all type-safety and _intent_ of target methods being used according to their appropriate types. It also means identifiers must be unique and overloads must be banned at compile time, or we risk reusing identifiers and not knowing which function to invoke. This again could be solved by separately shipping type identifiers, but this would mean reinventing what Swift's mangling scheme already does, but in a worse way. Instead, we propose to start with the simple mangling scheme, and in a subsequent proposal, address the versioning story more holistically, in a way that addresses ABI concerns of normal libraries, as well as distributed calls.
+
+We are aware that the mangling scheme makes the following, what should be possible to evolve without breaking APIs situations not work, that a different scheme could handle well:
+
+- adding parameters even with default parameters,
+- changing a type of argument from struct to class (or enum etc), is also breaking though it need not be.
+ - We could address this by omitting the kind information from the mangled names.
+
+The robust versioning and evolution scheme we have in mind for the future must be able to handle these cases, and we will be able to roll out a new identification scheme that handles those in the future, without breaking API or breaking existing remote calls. The metadata to lookup distributed method accessors would still be available using the "most precise" mangled format, even as we introduce a lossy, more versioning friendly format. APIs would remain unchanged, because from the perspective of `DistributedActorSystem` all it does is ship around an opaque String `identifier` of a remote call target.
+
+There are numerous other versioning and rollout topics to cover, such as "rolling deployments", "green/blue deployments" and other techniques that both the versioning scheme _and_ the specific actor system implementation must be able to handle eventually. However, based on experience implementing other actor systems in the past, we are confident that those are typical to add in later phases of such an endeavor, not as the first thing in the first iteration of the project.
+
+#### Compression techniques to avoid repeatedly sending large identifiers
+
+One of the worries brought up with regards to mangled names and string identifiers in general during the review has been that they can impose a large overhead when the actual messages are small. Specifically, as the `RemoteCallTarget.identifier` often can be quite large, and for distributed methods which e.g. accept only a few integers, or even no values at all, the identifiers often can dominate the entire message payload.
+
+This is not a novel problem – we have seen and solved such issues in the past in other actor runtimes (i.e. Akka). One potential solution is to establish a compression mechanism between peers where message exchanges establish shared knowledge about "long identifiers" and mapping them to unique numbers. The sender in such a system at first pessimistically sends the "long" String-based identifier, and in return may get additional metadata in the response "the next time you want to call this target, send the ID 12345". The sender system then stores in a cache that when invoking the "X...Z" target it does not need to send the long string identifier, but instead can send the number 12345. This solves the long string identifiers problem, as they need not be sent repeatedly over the wire. (There are a lot of details to how such schemes can be implemented that we do not need to dive into here, however we are confident those work well, because we have seen them solve this exact issue before).
+
+Given the need, and assuming other shared knowledge, we could even implement other identification schemes, which can also avoid that "initial" long string identifier sending. We will be exploring those as specific use-cases and requirements from adopters as they arise. We are confident in our ability to fit such techniques into this design because of the flexibility that APIs based around `RemoteCallTarget` gives us, without requiring us to actually send the entire target object over the wire.
+
+Such optimization techniques, are entirely implementable in concrete distributed actor system implementations. However, if necessary, we would be able to even extend the capabilities of `executeDistributedTarget` to accommodate other concrete needs and designs.
+
+#### Overlap with general ABI and versioning needs in normal Swift code
+
+The general concept binary/wire-compatible evolution of APIs by _adding_ new parameters to methods is not unique to distribution. In fact, this is a feature that would benefit ABI-stable libraries like the ones shipping with the SDK. It is often the case that new APIs are introduced that accept _more_ arguments, perhaps to enable or extend functionality of an existing feature. Developers today have to add new functions with "one more argument", like this:
+
+```swift
+public func f() {
+ f(x: 0)
+}
+
+@available(macOS 9999)
+public func f(x: Int) {
+ // new implementation
+}
+```
+
+Where the new function is going to ship with a new OS, yet actually contains an implementation that is compatible with the old definition of `f()`. In such situations, developers are forced to manually write forwarding methods. While this seems simple on small APIs, it can easily become rather complex and easy to introduce subtle bugs in the forwarding logic.
+
+Instead, developers would want to be able to introduce new parameters, with a default value that would be used when the function is invoked on older platforms, like this:
+
+```swift
+public func f(@available(macOS 9999) x: Int = 0) {
+ // new implementation
+}
+
+// compiler synthesizes:
+//
+// public func f() { self.f(x: 0) }
+//
+// @available(macOS 9999)
+// public func f( x: Int = 0) {
+```
+
+Where the compiler would synthesize versions of the methods for the various availabilities, and delegate, in an ABI-compatible way to the new implementation. This is very similar to what would be necessary to help wire-compatible evolution of distributed methods. So the same mechanisms could be used for distributed calls, if instead of OS versions, we could also allow application/node versions in the availability perhaps? This is not completely designed, but definitely a direction we are interested in exploring.
+
+#### Discussion: User provided target identities
+
+We also are considering, though are not yet convinced that these would be the optimal way to address some of the evolution concerns, the possibility to use "stable names". This mechanism would allow users to give full control over target identity to developers, where the `RemoteCallTarget.identifier` offered to the `remoteCall` implemented by a distributed actor system library, could be controlled by end users of the library, i.e. those who define distributed methods.
+
+On one hand, this gives great power to end-users, as they may use specific and minimal identifiers, even using `"A"` and other short names to minimize the impact of the identifiers to the payload size. On the other hand though, it opens up developers to a lot of risks, including conflicts in identifier use – a problem all to well known to objective-c developers where selectors could end up in similar problematic situations.
+
+We want to take time to design a proper system rather than just open up full control over the remote call target `identifier` to developers. We will aim to provide a flexible, and powerful mechanism, that does not risk giving developers easy ways to get shoot themselves in the foot. The design proposed here, is flexible enough to evolve.
+
+### Resolving `DistributedActor` protocols
+
+We want to be able to publish only protocols that contain distributed methods, and allow clients to resolve remote actors based on protocols alone, without having any knowledge about the specific `distributed actor` type implementing the protocol. This allows binary, closed-source frameworks to offer distributed actors as way of communication. Of course, for this to be viable we also need to solve the above ABI and wire-compatible evolution of distributed methods, assuming we solve those though, publishing distributed actor protocols is very useful and interesting for client/server scenarios, where the peers of a communication are not exact mirrors of the same process, but exhibit some asymmetry.
+
+Currently, we resolve distributed actors using the static method defined on the `DistributedActor` protocol, sadly this method is not possible to invoke on just a protocol:
+
+```swift
+protocol Greeter: DistributedActor {
+ func greet() -> String
+}
+
+let greeter: any Greeter = try Greeter.resolve(id: ..., using: websocketActorSystem)
+// ❌ error: static member 'resolve' cannot be used on protocol metatype 'Greeter.Protocol'
+```
+
+A "client" peer does not have to know what distributed actor exactly implements this protocol, just that we're able to send a "greet" message to it, we should be able to obtain an existential `any Greeter` and be able to invoke `greet()` on it.
+
+In order to facilitate this capability, we need to:
+
+- implement ad-hoc synthesis of a type that effectively works like a "stub" that other RPC systems generally source-generate, yet thanks to our actor model we're able to synthesize it in the compiler on demand;
+- find a way to invoke `resolve` on such protocol, for example we could offer a global function `resolveDistributedActorProtocol(Greeter.self, using: websocketActorSystem)`
+
+The `resolveDistributedActorProtocol` method has to be able to check the serialization requirement at compile-time where we invoke the resolve, because the distributed actor protocols don't have to declare a serialization requirement — they can, but they don't have to (and this is by design).
+
+It should be possible to resolve the following examples:
+
+```swift
+protocol Greeter: DistributedActor {
+ distribute func greet() -> String
+}
+
+final class WebsocketActorSystem: DistributedActorSystem {
+ typealias ActorID: WebsocketID // : Codable
+ typealias SerializationRequirement: Codable
+}
+
+... = try resolveDistributedActorProtocol(id: ..., as: Greeter.self, using: websocketActorSystem)
+```
+
+The resolve call would use the types defined for the `ActorID` and `SerializationRequirement` to see if this `Greeter` protocol is even implementable using these, i.e. if its distributed method parameters/return types do indeed conform to `Codable`, and if there isn't a conflict with regards to the actor ID.
+
+This means that we should reject at compile-time any attempts to resolve a protocol that clearly cannot be implemented over the actor system in question, for example:
+
+```swift
+protocol Greeter: DistributedActor {
+ distributed func greet() -> NotCodableResponse
+}
+
+final class WebsocketActorSystem: DistributedActorSystem {
+ typealias ActorID: WebsocketID // : Codable
+ typealias SerializationRequirement: Codable
+}
+
+... = try resolveDistributedActorProtocol(id: ..., as: Greeter.self, using: websocketActorSystem)
+// ❌ error: 'Greeter' cannot be resolved using 'WebsocketActorSystem'
+// ❌ error: result type 'NotCodableResponse' of distributed instance method does not conform to 'Codable'
+```
+
+These are the same checks that are performed on `distributed actor` declarations, but they are performed on the type. We can think of these checks running whenever distributed methods are "combined" with a specific actor system: this is the case in `distributed actor` declarations, as well as this protocol resolution time, because we're effectively creating a not-user-visible actor declaration that combines the given `DistributedActorSystem` with the synthesized "stub" distributed actor, so we need to run the checks here. Thankfully, we can run them at compile time, disallowing any ill-formed and impossible to implement combinations.
+
+### Passing parameters to `assignID`
+
+Sometimes, transports may need to get a little of configuration for a specific actor being initialized.
+
+Since `DistributedActorSystem.assignID` accepts the actor *type* it can easily access any configuration that is static for some specific actor type, e.g. like this:
+
+```swift
+protocol ConfiguredDistributedActor: DistributedActor {
+ static var globalServiceName: String { get }
+}
+
+distributed actor Cook: DistributedActorConfiguration {
+ static var globalServiceName: String { "com.apple.example.CookingService" }
+}
+```
+
+This way the `assignID` can detect the static property and e.g. ensure this actor is possible to look up by this static name:
+
+```swift
+extension SpecificDistributedActorSystem {
+ func assignID(_ type: Actor.Type) -> Actor.ID where Actor: DistributedActor {
+ let id = <>
+ if let C = type as ConfiguredDistributedActor.Type {
+ // for example, we could make sure the actor is discoverable using the service name:
+ let globalServiceName = C.globalServiceName
+ self.ensureAccessibleAs(id: id, as: globalServiceName)
+ }
+
+ return id
+ }
+}
+```
+
+Or similar configuration patterns. However, it is hard to implement a per instance configuration to be passed to the system.
+
+One way we could solve this is by introducing an `assignID` overload that accepts the `ActorConfiguration` that may be
+passed to the actor initializer, and would be passed along to the actor system like this:
+
+```swift
+extension SpecificDistributedActorSystem {
+ // associatedtype ActorConfiguration
+ func assignID(_ type: Actor.Type, _ properties: Self.ActorConfiguration) -> Actor.ID where Actor: DistributedActor {
+ if let name = properties.name {
+ return makeID(withName: name)
+ }
+
+ return makeRandomID()
+ }
+}
+```
+
+The creation of the actor would then be able to be passed at-most one `ActorConfiguration` instance, and that would be then passed down to this method:
+
+```swift
+distributed actor Worker {...}
+
+Worker(actorSystem: system, actorProperties: .name("worker-1234"))
+```
+
+Which can be *very* helpful since now IDs can have user provided information that are meaningful in the user's domain.
+
+## Alternatives considered
+
+This section summarizes various points in the design space for this proposal that have been considered, but ultimately rejected from this proposal.
+
+### Define `remoteCall` as protocol requirement, and accept `[Any]` arguments
+
+The proposal includes the fairly special `remoteCall` method that is expected to be present on a distributed actor system, however is not part of the protocol requirements because it cannot be nicely expressed in today's Swift, and it suffers from the lack of variadic generics (which are being worked on, see: [Pitching The Start of Variadic Generics](https://forums.swift.org/t/pitching-the-start-of-variadic-generics/51467)), however until they are complete, expressing `remoteCall` in the type-system is fairly painful, and we resort to providing multiple overloads of the method:
+
+```swift
+ func remoteCall(
+ on recipient: Actor,
+ method: DistributedMethodName,
+ _ arg1: P1,
+ throwing errorType: Failure.Type,
+ returning returnType: Success.Type
+ ) async throws -> Success where Actor: DistributedActor, Actor.ID = ActorID { ... }
+
+ func remoteCall(
+ on recipient: Actor,
+ method: DistributedMethodName,
+ _ arg1: P1, _ arg2: P2,
+ throwing errorType: Failure.Type,
+ returning returnType: Success.Type
+ ) async throws -> Success where Actor: DistributedActor, Actor.ID = ActorID { ... }
+
+ // ...
+```
+
+This is annoying for the few distributed actor system developers. However, it allows us to completely avoid any existential boxing that shuttling values through `Any` would imply. We are deeply interested in offering this system to systems that are very concerned about allocations, and runtime overheads, and believe this is the right tradeoff to make, while we await the arrival of variadic generics which will solve this system implementation annoyance.
+
+We are also able to avoid any heap allocations during the `remoteCall` thanks to this approach, as we do not have to construct type erased `arguments: [Any]` which would have been the alternative:
+
+```swift
+ func remoteCall(
+ on recipient: Actor,
+ method: DistributedMethodIdentifier,
+ _ args: [Any], // BAD
+ throwing errorType: Failure.Type,
+ returning returnType: Success.Type
+ ) async throws -> Success where Actor: DistributedActor, Actor.ID = ActorID { ... }
+```
+
+Not only that, but passing arguments as `[Any]` would force developers into using internal machinery to open the existentials (the not officially supported `_openExistential` feature), in order to obtain their specific types, and e.g. use `Codable` with them.
+
+### Constraining arguments, and return type with of `remoteCall` with `SerializationRequirement`
+
+Looking at the signature, one might be tempted to also include a `where` clause to statically enforce that all parameters and return type, conform to the `Self.SerializationRequirement`, like so:
+
+```swift
+ func remoteCall(
+ on recipient: Actor,
+ method: DistributedMethodName,
+ _ arg1: P1,
+ throwing errorType: Failure.Type,
+ returning returnType: Success.Type
+ ) async throws -> Success where Actor: DistributedActor,
+ Actor.ID = ActorID,
+ P1: SerializationRequirement { ... }
+// ❌ error: type 'P1' constrained to non-protocol, non-class type 'Self.R'
+```
+
+However, this is not expressible today in Swift, because we cannot prove the `associatedtype SerializationRequirement` can be used as constraint.
+
+Fixing this would require introducing new very advanced type system features, and after consultation with the core team we decided to accept this as a current implementation limitation.
+
+In practice this is not a problem, because the parameters are guaranteed to succeed being cast to `SerializationRequirement` at runtime thanks to the compile-time guarantee about parameters of distributed methods.
+
+### Hardcoding the distributed runtime to make use of `Codable`
+
+`Codable` is a great, useful, and relatively flexible protocol allowing for serialization of Swift native types. However, it may not always be the best serialization system available. For example, we currently do not have a great binary serialization format that works with `Codable`, or perhaps some developers just really want to use a 3rd party serialization format such as protocol buffers, SBE or something entirely custom.
+
+The additional complexity of the configurable `SerializationRequirement` is pulling its weight, and we are not interested in closing down the system to just use Codable.
+
+## Acknowledgments & Prior art
+
+We would like to acknowledge the prior art in the space of distributed actor systems which have inspired our design and thinking over the years. Most notably we would like to thank the Akka and Orleans projects, each showing independent innovation in their respective ecosystems and implementation approaches. As these are library-only solutions, they have to rely on wrapper types to perform the hiding of information, and/or source generation; we achieve the same goal by expanding the actor-isolation checking mechanisms already present in Swift.
+
+We would also like to acknowledge the Erlang BEAM runtime and Elixir language for a more modern take built upon the on the same foundations, which have greatly inspired our design, however take a very different approach to actor isolation (i.e. complete isolation, including separate heaps for actors).
+
+## Source compatibility
+
+This change is purely additive to the source language.
+
+The language impact has been mostly described in the Distributed Actor Isolation proposal
+
+## Effect on ABI stability
+
+TODO
+
+## Effect on API resilience
+
+None.
+
+## Changelog
+
+- 2.0 Adjustments after first round of review
+ - Expanded discussion on current semantics, and **future directions for versioning** and wire compatibility of remote calls.
+ - Amendment to **non-delegating distributed actor initializer semantics**
+ - Non-delegating Initializers no longer require a single `DistributedActorSystem` conforming argument to be passed, and automatically store and initialize the `self.id` with it.
+ - Instead, users must initialize the `self.actorSystem` property themselves.
+ - This should generally be done using the same pattern, by passing _in_ an actor system from the outside which helps in testing and stubbing out systems, however if one wanted to.
+ - However the actorSystem property is initialized, from an initializer parameter or some global value, task-local etc, the general initialization logic remains the same, and the compiler will inject the assignment of the `self.id` property.
+ - Useful error messages explaining this decision are reported if users attempt to assign to the `id` property directly.
+
+ - Thanks to YR Chen for recognizing this limitation and helping arrive at a better design here.
+
+ - **Removal of explicit use of mangled names** in the APIs, and instead all APIs use an opaque `RemoteCallTarget` that carries an opaque String `identifier`
+ - The `RemoteCallTarget` is populated by the compiler using mangled names by default, but other schemes can be used in the future
+ - The `RemoteCallTarget` now pretty prints as "`hello(name:surname:)`" if able to decode the target from the identifier, otherwise it prints the identifier directly. This can be used to include pretty names of call targets in tracing systems etc.
+ - This design future-proofs the APIs towards potential new encoding schemed we might come up in the future as we tackle a proper and feature complete versioning story for distributed calls.
+
+ - `recordArgument` is passed a **`RemoteCallArgument`** which carries additional information about the argument in question
+ - This parameter can be either ignored, or stored along the serialized format which may be useful for non swift targets of invocations. E.g. it is possible to store an invocation as JSON object where the argument names are used as labels or similar patterns.
+ - Thanks to Slava Pestov for suggesting this improvement.
+
+- 1.3 Larger revision to match the latest runtime developments
+ - recording arguments does not need to write into provided pointers; thanks to the calls being made in IRGen, we're able to handle things properly even without the heterogenous buffer approach. Thank you, Pavel Yaskevich
+ - simplify rules of readying actors across synchronous and asynchronous initializers, we can always ready "just before `self` is escaped", in either situation; This is thanks to the latest developments in actor initializer semantics. Thank you, Kavon Farvardin
+ - express recording arguments and remote calls as "ad-hoc" requirements which are invoked directly by the compiler
+ - various small cleanups to reflect the latest implementation state
+- 1.2 Drop implicitly distributed methods
+- 1.1 Implicitly distributed methods
+- 1.0 Initial revision
+- [Pitch: Distributed Actors](https://forums.swift.org/t/pitch-distributed-actors/51669)
+ - Which focused on the general concept of distributed actors, and will from here on be cut up in smaller, reviewable pieces that will become their own independent proposals. Similar to how Swift Concurrency is a single coherent feature, however was introduced throughout many interconnected Swift Evolution proposals.
+
+[isolation]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0336-distributed-actor-isolation.md
diff --git a/proposals/0345-if-let-shorthand.md b/proposals/0345-if-let-shorthand.md
new file mode 100644
index 0000000000..265d89d873
--- /dev/null
+++ b/proposals/0345-if-let-shorthand.md
@@ -0,0 +1,382 @@
+# `if let` shorthand for shadowing an existing optional variable
+
+* Proposal: [SE-0345](0345-if-let-shorthand.md)
+* Author: [Cal Stephens](https://github.com/calda)
+* Review Manager: [Doug Gregor](https://github.com/DougGregor)
+* Status: **Implemented (Swift 5.7)**
+* Decision Notes: [Rationale](https://forums.swift.org/t/accepted-se-0345-if-let-shorthand-for-shadowing-an-existing-optional-variable/56364)
+* Implementation: [apple/swift#40694](https://github.com/apple/swift/pull/40694)
+
+## Introduction
+
+Optional binding using `if let foo = foo { ... }`, to create an unwrapped variable that shadows an existing optional variable, is an extremely common pattern. This pattern requires the author to repeat the referenced identifier twice, which can cause these optional binding conditions to be verbose, especially when using lengthy variable names. We should introduce a shorthand syntax for optional binding when shadowing an existing variable:
+
+```swift
+let foo: Foo? = ...
+
+if let foo {
+ // `foo` is of type `Foo`
+}
+```
+
+Swift-evolution thread: [`if let` shorthand](https://forums.swift.org/t/if-let-shorthand/54230)
+
+## Motivation
+
+Reducing duplication, especially of lengthy variable names, makes code both easier to write _and_ easier to read.
+
+For example, this statement that unwraps `someLengthyVariableName` and `anotherImportantVariable` is rather arduous to read (and was without a doubt arduous to write):
+
+```swift
+let someLengthyVariableName: Foo? = ...
+let anotherImportantVariable: Bar? = ...
+
+if let someLengthyVariableName = someLengthyVariableName, let anotherImportantVariable = anotherImportantVariable {
+ ...
+}
+```
+
+One approach for dealing with this is to use shorter, less descriptive, names for the unwrapped variables:
+
+```swift
+if let a = someLengthyVariableName, let b = anotherImportantVariable {
+ ...
+}
+```
+
+This approach, however, reduces clarity at the point of use for the unwrapped variables. Instead of encouraging short variable names, we should allow for the ergonomic use of descriptive variable names.
+
+## Proposed solution
+
+If we instead omit the right-hand expression, and allow the compiler to automatically shadow the existing variable with that name, these optional bindings are much less verbose, and noticeably easier to read / write:
+
+```swift
+let someLengthyVariableName: Foo? = ...
+let anotherImportantVariable: Bar? = ...
+
+if let someLengthyVariableName, let anotherImportantVariable {
+ ...
+}
+```
+
+This is a fairly natural extension to the existing syntax for optional binding conditions.
+
+## Detailed design
+
+Specifically, this proposal extends the Swift grammar for [`optional-binding-condition`](https://docs.swift.org/swift-book/ReferenceManual/Statements.html#grammar_optional-binding-condition)s.
+
+This is currently defined as:
+
+> optional-binding-condition → **let** [pattern](https://docs.swift.org/swift-book/ReferenceManual/Patterns.html#grammar_pattern) [initializer](https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#grammar_initializer) | **var** [pattern](https://docs.swift.org/swift-book/ReferenceManual/Patterns.html#grammar_pattern) [initializer](https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#grammar_initializer)
+
+and would be updated to:
+
+> optional-binding-condition → **let** [pattern](https://docs.swift.org/swift-book/ReferenceManual/Patterns.html#grammar_pattern) [initializer](https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#grammar_initializer)opt | **var** [pattern](https://docs.swift.org/swift-book/ReferenceManual/Patterns.html#grammar_pattern) [initializer](https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#grammar_initializer)opt
+
+This would apply to all conditional control flow statements:
+
+```swift
+if let foo { ... }
+if var foo { ... }
+
+else if let foo { ... }
+else if var foo { ... }
+
+guard let foo else { ... }
+guard var foo else { ... }
+
+while let foo { ... }
+while var foo { ... }
+```
+
+The compiler would synthesize an initializer expression that references the variable being shadowed.
+
+For example:
+
+```swift
+if let foo { ... }
+```
+
+is transformed into:
+
+```swift
+if let foo = foo { ... }
+```
+
+Explicit type annotations are permitted, like with standard optional binding conditions.
+
+For example:
+
+```swift
+if let foo: Foo { ... }
+```
+
+is transformed into:
+
+```swift
+if let foo: Foo = foo { ... }
+```
+
+The pattern following the introducer serves as both an evaluated expression _and_ an identifier for the newly-defined non-optional variable. Existing precedent for this type of syntax includes closure capture lists, which work the same way:
+
+```swift
+let foo: Foo
+let closure = { [foo] in // `foo` is both an expression and the identifier
+ ... // for a new variable defined within the closure
+}
+```
+
+Because of this, only valid identifiers would be permitted with this syntax. For example, this example would not be valid:
+
+```swift
+if let foo.bar { ... } // 🛑 unwrap condition requires a valid identifier
+ ^ // fix-it: insert `<#identifier#> = `
+```
+
+### Interaction with implicit self
+
+Like with existing optional bindings, this new syntax would support implifict self references to unwrap optional members of `self`. For example, the usage in this example would be permitted:
+
+```swift
+struct UserView: View {
+ let name: String
+ let emailAddress: String?
+
+ var body: some View {
+ VStack {
+ Text(user.name)
+
+ // Equivalent to `if let emailAddress = emailAddress { ... }`,
+ // unwraps `self.emailAddress`.
+ if let emailAddress {
+ Text(emailAddress)
+ }
+ }
+ }
+}
+```
+
+## Source compatibility
+
+This change is purely additive and does not break source compatibility of any valid existing Swift code.
+
+## Effect on ABI stability
+
+This change is purely additive, and is a syntactic transformation to existing valid code, so has no effect on ABI stability.
+
+## Effect on API resilience
+
+This change is purely additive, and is a syntactic transformation to existing valid code, so has no effect on ABI stability.
+
+## Future directions
+
+### Optional casting
+
+A natural extension of this new syntax could be to support shorthand for optional casting. For example:
+
+`if let foo as? Bar { ... }`
+
+could be equivalent to:
+
+`if let foo = foo as? Bar { ... }`
+
+This is not included in this proposal, but is a reasonable feature that could be added in the future.
+
+### Interaction with future borrow introducers
+
+["A roadmap for improving Swift performance predictability"](https://forums.swift.org/t/a-roadmap-for-improving-swift-performance-predictability-arc-improvements-and-ownership-control/54206#borrow-variables-7) discusses potential new `ref` and `inout` introducers for creating variables that "borrow" existing variables without making a copy (by enforcing exclusive access). For consistency with `let` / `var`, it will likely make sense to support optional binding conditions for these new introducers:
+
+```swift
+if ref foo = foo {
+ // if `foo` is not nil, it is borrowed and made available as a non-optional, immutable variable
+}
+
+if inout foo = &foo {
+ // if `foo` is not nil, it is borrowed and made available as a non-optional, mutable variable
+}
+```
+
+The shorthand syntax for `let` / `var` optional bindings would extend fairly naturally to these new introducers:
+
+```swift
+if ref foo {
+ // if `foo` is not nil, it is borrowed and made available as a non-optional, immutable variable
+}
+
+if inout &foo {
+ // if `foo` is not nil, it is borrowed and made available as a non-optional, mutable variable
+}
+```
+
+### Unwrapping nested members of objects
+
+This proposal doesn't permit shorthand unwrapping for members nested in other objects. For example:
+
+`if let foo.bar { ... } // 🛑`
+
+There are a few different options that could allow us to support this type of syntax in the future.
+
+One approach could be to automatically synthesize the identifier name for the unwrapped variable in the inner scope. For example. `if let foo.bar` could introduce a new non-optional variable named `bar` or `fooBar`.
+
+Another approach could be to permit this for potential future borrow introducers `ref` and `inout` (from ["A roadmap for improving Swift performance predictability"](https://forums.swift.org/t/a-roadmap-for-improving-swift-performance-predictability-arc-improvements-and-ownership-control/54206#borrow-variables-7)). These borrows would have compiler-enforced exclusive access to the underlying storage, so they technically do not require a unique identifier name for the inner scope. This could allow us to unwrap members of objects without any new variables or copies. For example:
+
+```swift
+// `mother.father.sister` is optional
+
+if ref mother.father.sister {
+ // `mother.father.sister` is non-optional and immutable
+}
+
+if inout &mother.father.sister {
+ // `mother.father.sister` is non-optional and mutable
+}
+```
+
+## Alternatives considered
+
+There have been many other proposed spellings for this feature:
+
+### `if foo`
+
+The briefest possible spelling for this feature would just be a bare `if foo` condition. This spelling, however, would create ambiguity between optional unwrapping conditions and boolean conditions, and could lead to confusing / conter-intuitive situations:
+
+```swift
+let foo: Bool = true
+let bar: Bool? = false
+
+if foo, bar {
+ // would succeed
+}
+
+if foo == true, bar == true {
+ // would fail
+}
+```
+
+To avoid this ambiguity, we need some sort of distinct syntax for optional bindings.
+
+### `if unwrap foo`
+
+Another option is to introduce a new keyword or sigil for this purpose, like `if unwrap foo`, `if foo?` or `if have foo`.
+
+A key benefit of introducing a completely new syntax like `if unwrap foo` is that it gives us the opportunity to also revisit the _semantics_ of how optional binding conditions actually work. Today, optional binding conditions always make a copy of the value. From a performance perspective, it would be more efficient to perform a _borrow_ instead of a copy.
+
+["A roadmap for improving Swift performance predictability"](https://forums.swift.org/t/a-roadmap-for-improving-swift-performance-predictability-arc-improvements-and-ownership-control/54206#borrow-variables-7) discusses potential future introducers `ref` (to perform an immutable borrow) and `inout` (to perform a mutable borrow). For consistency with `let` / `var`, it will likely make sense to support optional binding conditions for these new introducers:
+
+```swift
+if ref foo = foo {
+ // if `foo` is not nil, it is borrowed and made available as a non-optional, immutable variable
+}
+
+if inout foo = &foo {
+ // if `foo` is not nil, it is borrowed and made available as a non-optional, mutable variable
+}
+```
+
+Instead of being shorthand for `if let`, this new shorthand syntax could instead be shorthand for `if ref`. This would improve performance in general, and could nudge users towards using borrows instead of copies (since only the borrow form would receive shorthand sugar).
+
+A key downside of borrows, however, is that they require exclusive access to the borrowed variable. Memory exclusivity violations will result in compiler errors in some cases, but can also manifest as runtime errors in more complex cases. For example:
+
+```swift
+var x: Int? = 1
+
+func increment(by number: Int) {
+ x? += number
+}
+
+if ref x = x {
+ increment(by: x)
+}
+```
+
+This would trap at runtime, because `increment(by:)` would attempt to modify the value of `x` while it is already being borrowed by the `if ref x = x` optional binding condition.
+
+Once borrow introducers are added to the language, seeing `ref x` or `inout x` anywhere in Swift will serve as an important visual marker about the exclusivity requirements of the code. On the other hand, a new syntax like `if unwrap x` doesn't explicitly indicate that the variable is being borrowed. This could lead to users being surprised by unexpected exclusivity violations, which could cause confusing compile-time errors or runtime crashes.
+
+Borrow introducers will be very useful, but adopting them is a tradeoff between performance and conceptual overhead. Borrows are cheap but come with high conceptual overhead. Copies can be expensive but always work as expected without much extra thought. Given this tradeoff, it likely makes sense for this shorthand syntax to provide a way for users to choose between performing a copy or performing a borrow, rather than limiting users to one or the other.
+
+Additionally, for consistency with existing optional binding conditions, this new shorthand should support the distinction between immutable and mutable variables. Combined with the distinction between copies and borrows, that would give us the same set of options as normal variables:
+
+```swift
+// Included in this proposal:
+if let foo { /* foo is an immutable copy */ }
+if var foo { /* foo is a mutable copy */ }
+
+// Potentially added in the future:
+if ref foo { /* foo is an immutable borrow */ }
+if inout &foo { /* foo is a mutable borrow */ }
+```
+
+Since we already have syntax for these concepts, we should reuse that syntax in this shorthand rather than create a new syntax that is less expressive (e.g. only supports a subset of the available options) and less explicit (e.g. that users would have to memorize whether this new shorthand performs a copy or a borrow).
+
+### `if let foo?`
+
+Another option is to include a `?` to explicitly indicate that this is unwrapping an optional, using `if let foo?`. This is indicative of the existing `case let foo?` pattern matching syntax.
+
+`if let foo = foo` (the most common existing syntax for this) unwraps optionals without an explicit `?`. This implies that a conditional optional binding is sufficiently clear without a `?` to indicate the presence of an optional. If this is the case, then an additional `?` is likely not strictly necessary in the shorthand `if let foo` case.
+
+While the symmetry of `if let foo?` with `case let foo?` is nice, consistency with `if let foo = foo` is even more important condiering they will more frequently appear within the same statement:
+
+```swift
+// Consistent
+if let user, let defaultAddress = user.shippingAddresses.first { ... }
+
+// Inconsistent
+if let user?, let defaultAddress = user.shippingAddresses.first { ... }
+```
+
+Additionally, the `?` symbol makes it trickier to support explicit type annotations like in `if let foo: Foo = foo`. `if let foo: Foo` is a natural consequence of the existing grammar. It's less clear how this would work with an additional `?`. `if let foo?: Foo` likely makes the most sense, but doesn't match any existing language constructs.
+
+### `if foo != nil`
+
+One somewhat common proposal is to permit `nil`-checks (like `if foo != nil`) to unwrap the variable in the inner scope. Kotlin supports this type of syntax:
+
+```kt
+var foo: String? = "foo"
+print(foo?.length) // "3"
+
+if (foo != null) {
+ // `foo` is non-optional
+ print(foo.length) // "3"
+}
+```
+
+This pattern in Kotlin _does not_ define a new variable -- it merely changes the type of the existing variable within the inner scope. So mutations that affect the inner scope also affect the outer scope:
+
+```kt
+var foo: String? = "foo"
+
+if (foo != null) {
+ print(foo) // "foo"
+ foo = "bar"
+ print(foo) // "bar"
+}
+
+print(foo) // "bar"
+```
+
+This is different from Swift's optional binding conditions (`if let foo = foo`), which define a new, _separate_ variable in the inner scope. This is a defining characteristic of optional binding conditions in Swift, so any shorthand syntax must make it abundantly clear that a new variable is being declared.
+
+### Don't permit `if var foo`
+
+Since `if var foo = foo` is significantly less common than `if let foo = foo`, we could potentially choose to _not_ support `var` in this shorthand syntax.
+
+`var` shadowing has the potential to be more confusing than `let` shadowing -- `var` introduces a new _mutable_ variable, and any mutations to the new variable are not shared with the original optional variable. On the other hand, `if var foo = foo` already exists, and it seems unlikely that `if var foo` would be more confusing / less clear than the existing syntax.
+
+Since `let` and `var` are interchangeable elsewhere in the language, that should also be the case here -- disallowing `if var foo` would be inconsistent with existing optional binding condition syntax. If we were using an alternative spelling that _did not_ use `let`, it may be reasonable to exclude `var` -- but since we are using `let` here, `var` should also be allowed.
+
+## Acknowledgments
+
+Many thanks to Craig Hockenberry, who recently wrote about this topic in [Let’s fix `if let` syntax](https://forums.swift.org/t/lets-fix-if-let-syntax/48188) which directly informed this proposal.
+
+Thanks to Ben Cohen for suggesting the alternative `if let foo?` spelling, and for providing valuable feedback on this proposal during the pitch phase.
+
+Thanks to Chris Lattner for suggesting to consider how this proposal should interact with upcoming language features like potential `ref` and `inout` borrow introducers.
+
+Thanks to [tera](https://forums.swift.org/u/tera/summary) for suggesting the alternative `if foo` spelling.
+
+Thanks to Jon Shier for providing the SwiftUI optional binding example.
+
+Thanks to James Dempsey for providing the "consistency with existing optional binding conditions" example.
+
+Thanks to Frederick Kellison-Linn for pointing out that variables in closure capture lists are an existing precedent for this type of syntax.
diff --git a/proposals/0346-light-weight-same-type-syntax.md b/proposals/0346-light-weight-same-type-syntax.md
new file mode 100644
index 0000000000..7199446d35
--- /dev/null
+++ b/proposals/0346-light-weight-same-type-syntax.md
@@ -0,0 +1,496 @@
+# Lightweight same-type requirements for primary associated types
+
+* Proposal: [SE-0346](0346-light-weight-same-type-syntax.md)
+* Authors: [Pavel Yaskevich](https://github.com/xedin), [Holly Borla](https://github.com/hborla), [Slava Pestov](https://github.com/slavapestov)
+* Review Manager: [John McCall](https://github.com/rjmccall)
+* Status: **Implemented (Swift 5.7)**
+* Previous Revisions: [1st](https://github.com/swiftlang/swift-evolution/blob/5d86d57cfd6d803df4da90b196682d495e5de9b9/proposals/0346-light-weight-same-type-syntax.md)
+* Review: ([first pitch](https://forums.swift.org/t/pitch-light-weight-same-type-constraint-syntax/52889)) ([second pitch](https://forums.swift.org/t/pitch-2-light-weight-same-type-requirement-syntax/55081)) ([first review](https://forums.swift.org/t/se-0346-lightweight-same-type-requirements-for-primary-associated-types/55869)) ([second review](https://forums.swift.org/t/se-0346-second-review-lightweight-same-type-requirements-for-primary-associated-types/56414)) ([acceptance](https://forums.swift.org/t/accepted-se-0346-lightweight-same-type-requirements-for-primary-associated-types/56747))
+
+## Introduction
+
+As a step toward the goal of improving the UI of generics outlined in [Improving the UI of Generics](https://forums.swift.org/t/improving-the-ui-of-generics/22814#heading--directly-expressing-constraints), this proposal introduces a new syntax for conforming a generic parameter and constraining an associated type via a same-type requirement.
+
+## Motivation
+
+Consider a function that returns a `Sequence` of lines in a source file:
+
+```swift
+struct LineSequence : Sequence {
+ struct Iterator : IteratorProtocol {
+ mutating func next() -> String? { ... }
+ }
+
+ func makeIterator() -> Iterator {
+ return Iterator()
+ }
+}
+
+func readLines(_ file: String) -> LineSequence { ... }
+```
+
+Suppose you are implementing a syntax highlighting library. You might define another function which wraps the result in a `SyntaxTokenSequence`, whose element type is `[Token]`, representing an array of syntax-highlighted tokens on each line:
+
+```swift
+func readSyntaxHighlightedLines(_ file: String)
+ -> SyntaxTokenSequence {
+ ...
+}
+```
+
+At this point, the concrete result type is rather complex, and we might wish to hide it behind an opaque result type using the `some` keyword:
+
+```swift
+func readSyntaxHighlightedLines(_ file: String) -> some Sequence {
+ ...
+}
+```
+
+However, the resulting definition of `readSyntaxHighlightedLines()` is not as useful as the original, because the requirement that the `Element` associated type of the resulting `Sequence` is equal to `[Token]` cannot be expressed.
+
+As another example, consider a global function `concatenate` that operates on two arrays of `String`:
+
+```swift
+func concatenate(_ lhs: Array, _ rhs: Array) -> Array {
+ ...
+}
+```
+
+To generalize this function to arbitrary sequences, one might write:
+
+```swift
+func concatenate
(_ lhs: S, _ rhs: S) -> S where S.Element == String {
+ ...
+}
+```
+
+However, while `where` clauses are very general and allow complex generic requirements to be expressed, they also introduce cognitive overhead when reading and writing the declaration, and looks quite different than the concrete implementation where the type was simply written as `Array`. It would be nice to have a simpler solution for cases where there is only a single same-type requirement, as above.
+
+## Proposed solution
+
+We’d like to propose a new syntax for declaring a protocol conformance requirement together with one or more same-type requirements on the protocol's _primary associated types_. This new syntax looks like the application of a concrete generic type to a list of type arguments, allowing you to write `Sequence` or `Sequence<[Token]>`. This builds on the user's previous intuition and understanding of generic types and is analogous to `Array` and `Array<[Token]>`.
+
+Protocols can declare one or more primary associated types using a syntax similar to a generic parameter list of a concrete type:
+
+```swift
+protocol Sequence {
+ associatedtype Element
+ associatedtype Iterator : IteratorProtocol
+ where Element == Iterator.Element
+ ...
+}
+
+protocol DictionaryProtocol {
+ associatedtype Key : Hashable
+ associatedtype Value
+ ...
+}
+```
+
+A protocol with primary associated types can be written with a list of type arguments in angle brackets, from any position where a protocol conformance requirement was previously allowed.
+
+For example, an opaque result type can now constrain the primary associated type:
+
+```swift
+func readSyntaxHighlightedLines(_ file: String) -> some Sequence<[Token]> {
+ ...
+}
+```
+
+The `concatenate()` function shown earlier can now be written like this:
+
+```swift
+func concatenate>(_ lhs: S, _ rhs: S) -> S {
+ ...
+}
+```
+
+Primary associated types are intended to be used for associated types which are usually provided by the caller. These associated types are often witnessed by generic parameters of the conforming type. For example, `Element` is a natural candidate for the primary associated type of `Sequence`, since `Array` and `Set` both conform to `Sequence`, with the `Element` associated type witnessed by a generic parameter in the corresponding concrete types. This introduces a clear correspondence between the constrained protocol type `Sequence` on one hand and the concrete types `Array`, `Set` on the other hand.
+
+## Detailed design
+
+At the protocol declaration, an optional _primary associated types list_ delimited by angle brackets can follow the protocol name. When present, at least one primary associated type must be named. Multiple primary associated types are separated by commas. Each entry in the primary associated type list must name an existing associated type declared in the body of the protocol or one of its inherited protocols. The formal grammar is amended as follows, adding an optional **primary-associated-type-list** production to **protocol-declaration**:
+
+- **protocol-declaration** → attributesopt access-level-modifieropt `protocol` protocol-name primary-associated-type-listopt type-inheritance-clauseopt generic-where-clauseopt protocol-body
+- **primary-associated-type-list** → `<` primary-associated-type-entry `>`
+- **primary-associated-type-entry** → primary-associated-type | primary-associated-type `,` primary-associated-type-entry
+- **primary-associated-type** → type-name
+
+Some examples:
+
+```swift
+// Primary associated type 'Element' is declared inside the protocol
+protocol SetProtocol {
+ associatedtype Element : Hashable
+ ...
+}
+
+protocol SortedMap {
+ associatedtype Key
+ associatedtype Value
+}
+
+// Primary associated types 'Key' and 'Value' are declared inside
+// the inherited 'SortedMap' protocol
+protocol PersistentSortedMap : SortedMap {
+ ...
+}
+```
+
+At the usage site, a _constrained protocol type_ may be written with one or more type arguments, like `P`. Omitting the list of type arguments altogether is permitted, and leaves the protocol unconstrained. Specifying fewer or more type arguments than the number of primary associated types is an error. Adding a primary associated type list to a protocol is a source-compatible change; the protocol can still be referenced without angle brackets as before.
+
+### Constrained protocols in desugared positions
+
+An exhaustive list of positions where the constrained protocol syntax may appear follows. In the first set of cases, the new syntax is equivalent to the existing `where` clause syntax with a same-type requirement constraining the primary associated types.
+
+- The extended type of an extension, for example:
+
+ ```swift
+ extension Collection { ... }
+
+ // Equivalent to:
+ extension Collection where Element == String { ... }
+ ```
+
+- The inheritance clause of another protocol, for example:
+
+ ```swift
+ protocol TextBuffer : Collection { ... }
+
+ // Equivalent to:
+ protocol TextBuffer : Collection where Element == String { ... }
+ ```
+
+- The inheritance clause of a generic parameter, for example:
+
+ ```swift
+ func sortLines>(_ lines: S) -> S
+
+ // Equivalent to:
+ func sortLines(_ lines: S) -> S
+ where S.Element == String
+ ```
+
+- The inheritance clause of an associated type, for example:
+
+ ```swift
+ protocol Document {
+ associatedtype Lines : Collection
+ }
+
+ // Equivalent to:
+ protocol Document {
+ associatedtype Lines : Collection
+ where Lines.Element == String
+ }
+ ```
+
+- The right-hand side of a conformance requirement in a `where` clause, for example:
+
+ ```swift
+ func merge(_ sequences: S)
+ where S.Element : Sequence
+
+ // Equivalent to:
+ func merge(_ sequences: S)
+ where S.Element : Sequence, S.Element.Element == String
+ ```
+
+- An opaque parameter declaration (see [SE-0341 Opaque Parameter Declarations](0341-opaque-parameters.md)):
+
+ ```swift
+ func sortLines(_ lines: some Collection)
+
+ // Equivalent to:
+ func sortLines>(_ lines: C)
+
+ // In turn equivalent to:
+ func sortLines(_ lines: C)
+ where C.Element == String
+ ```
+
+- The protocol arguments can contain nested opaque parameter declarations. For example,
+
+ ```swift
+ func sort(elements: inout some Collection) {}
+
+ // Equivalent to:
+ func sort(elements: inout C) {}
+ where C.Element == E
+ ```
+
+When referenced from one of the above positions, a conformance requirement `T : P` desugars to a conformance requirement `T : P` followed by one or more same-type requirements:
+
+```swift
+T : P
+T.PrimaryType1 == Arg1
+T.PrimaryType2 == Arg2
+...
+```
+
+If the right hand side `Arg1` is itself an opaque parameter type, a fresh generic parameter is introduced for use as the right-hand side of the same-type requirement. See [SE-0341 Opaque Parameter Declarations](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0341-opaque-parameters.md) for details.
+
+### Constrained protocols in opaque result types
+
+- A constrained protocol may appear in an opaque result type specified by the `some` keyword. In this case, the syntax actually allows you to express something that was previously not possible to write, since we do not allow `where` clauses on opaque result types:
+
+ ```swift
+ func transformElements, E>(_ lines: S) -> some Sequence
+ ```
+
+ This example also demonstrates that the argument can itself depend on generic parameters from the outer scope.
+
+ The [SE-0328 Structural Opaque Result Types](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0328-structural-opaque-result-types.md) pitch allows multiple occurrences of `some` in a return type. This generalizes to constrained protocol types, whose constraint can be another opaque result type:
+
+ ```swift
+ func transform(_: some Sequence) -> some Sequence
+ ```
+
+ Note that in the above, the opaque result type `some Sequence` is unrelated to the opaque _parameter_ type `some Sequence`. The parameter type is provided by the caller. The opaque result type is a (possibly different) homogeneous sequence of elements, where the element type is known to conform to `some Equatable` but is otherwise opaque to the caller.
+
+### Other positions
+
+There are three more places where constrained protocols may appear:
+
+- In the inheritance clause of a concrete type, for example:
+
+ ```swift
+ struct Lines : Collection { ... }
+ ```
+
+ In this position it is sugar for specifying the associated type witness, similar to explicitly declaring a typealias:
+
+ ```swift
+ struct Lines : Collection {
+ typealias Element = String
+ }
+ ```
+
+- As the underlying type of a typealias:
+
+ ```swift
+ typealias SequenceOfInt = Sequence
+ ```
+
+ The typealias may be used in any position where the constrained protocol type itself would be used.
+
+- As a member of a protocol composition, when the protocol composition appears in any position where a constrained protocol type would be valid:
+
+ ```swift
+ func takeEquatableSequence(_ seqs: some Sequence & Equatable) {}
+ ```
+
+### Unsupported positions
+
+A natural generalization is to enable this syntax for existential types, e.g. `any Collection`. This is a larger feature that needs careful consideration of type conversion behaviors. It will also require runtime support for metadata and dynamic casts. For this reason it will be covered by a separate proposal.
+
+## Alternatives considered
+
+### Treat primary associated type list entries as declarations
+
+In an earlier revision of this proposal, the associated type list entries would declare new associated types, instead of naming associated types declared in the body. That is, you would write
+
+```swift
+protocol SetProtocol {
+ ...
+}
+```
+
+instead of
+
+```swift
+protocol SetProtocol {
+ associatedtype Key : Hashable
+ ...
+}
+```
+
+We felt that allowing declaration of associated types in the primary associated type list promotes confusion that what’s actually happening here is a generic declaration, when it is semantically different in important ways. Another potential source of confusion would be if a primary associated type declared a default type witness:
+
+```swift
+protocol SetProtocol {
+ ...
+}
+```
+
+This makes it look like a "defaulted generic parameter", which it is not; writing `SetProtocol` means leaving `Key` unconstrained, and is not the same as `SetProtocol`. The new form makes it clearer that what is going on here is that a default is being declared for conformances to the protocol, and not for the usage site of the generic constraint:
+
+```swift
+protocol SetProtocol {
+ associatedtype Key : Hashable = String
+ ...
+}
+```
+
+### Require associated type names, e.g. `Collection<.Element == String>`
+
+Explicitly writing associated type names to constrain them in angle brackets has a number of benefits:
+
+* Doesn’t require any special syntax at the protocol declaration.
+* Explicit associated type names allows constraining arbitrary associated types.
+
+There are also a number of drawbacks to this approach:
+
+* No visual clues at the protocol declaration about what associated types are useful.
+* The use-site may become onerous. For protocols with only one primary associated type, having to specify the name of it is unnecessarily repetitive.
+* The syntax can be confusing when the constrained associated type has the same name as a generic parameter of the declaration. For example, the following:
+
+ ```swift
+ func adjacentPairs(_: some Sequence,
+ _: some Sequence)
+ -> some Sequence<(Element, Element)> {}
+ ```
+
+ reads better than the hypothetical alternative:
+
+ ```swift
+ func adjacentPairs(_: some Sequence<.Element == Element>,
+ _: some Sequence<.Element == Element>)
+ -> some Sequence<.Element == (Element, Element)> {}
+ ```
+
+* This more verbose syntax is not as clear of an improvement over the existing syntax today, because most of the where clause is still explicitly written. This may also encourage users to specify most or all generic constraints in angle brackets at the front of a generic signature instead of in the `where` clause, violates a core tenet of [SE-0081 Move where clause to end of declaration](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0081-move-where-expression.md).
+
+* Finally, this syntax lacks the symmetry between concrete types and generic types; generalizing from `Array` requires learning and writing the novel syntax `some Collection<.Element == Int>` instead of simply `some Collection`.
+
+Note that nothing in this proposal _precludes_ adding the above syntax in the future; the presence of a leading dot (or some other signifier) should allow unambiguous parsing in either case.
+
+### Implement more general syntax for opaque result type requirements first
+
+As previously mentioned, in the case of opaque result types, this proposal introduces new expressive power, since opaque result types cannot have a `where` clause where a same-type requirement on a primary associated type could otherwise be written.
+
+It would be possible to first introduce a language feature allowing general requirements on opaque result types. One such possibility is "named opaque result types", which can have requirements imposed upon them in a `where` clause:
+
+```swift
+func readLines(_ file: String) -> some Sequence { ... }
+
+// Equivalent to:
+func readLines(_ file: String) -> S
+ where S : Sequence, S.Element == String { ... }
+```
+
+However, the goal of this proposal is to make generics more approachable by introducing a symmetry between concrete types and generics, and make generics feel more like a generalization of what programmers coming from other languages are already familiar with.
+
+A more general syntax for opaque result types can be considered on its own merits, and as with the `some Collection<.Element == Int>` syntax discussed in the previous section, nothing in this proposal precludes opaque result types from being generalized further in the future.
+
+### Annotate regular `associatedtype` declarations with `primary`
+
+Adding some kind of modifier to `associatedtype` declaration shifts complexity to the users of an API because it’s still distinct from how generic types declare their parameters, which goes against the progressive disclosure principle, and, if we choose to generalize this proposal to multiple primary associated types in the future, requires an understanding of ordering on the use-site.
+
+This would also make declaration order significant, in a way that is not currently true for the members of a protocol definition.
+
+Annotation of associated type declarations could make it easier to conditionally declare a protocol which defines primary associated types in newer compiler versions only. The syntax described in this proposal applies to the protocol declaration itself. As a consequence, a library wishing to adopt this feature in a backwards-compatible manner must duplicate entire protocol definitions behind `#if` blocks:
+
+```swift
+#if swift(>=5.7)
+protocol SetProtocol {
+ associatedtype Element : Hashable
+
+ var count: Int { get }
+ ...
+}
+#else
+protocol SetProtocol {
+ associatedtype Element : Hashable
+
+ var count: Int { get }
+ ...
+}
+#endif
+```
+
+With a hypothetical `primary` keyword, only the primary associated types must be duplicated:
+
+```swift
+protocol SetProtocol {
+#if swift(>=5.7)
+ primary associatedtype Element : Hashable
+#else
+ associatedtype Element : Hashable
+#if
+
+ var count: Int { get }
+ ...
+}
+```
+
+However, duplicating the associated type declaration in this manner is still an error-prone form of code duplication, and it makes the code harder to read. We feel that this use case should not unnecessarily hinder the evolution of the language syntax. The concerns of libraries adopting new language features while remaining compatible with older compilers is not unique to this proposal, and would be best addressed with a third-party pre-processor tool.
+
+With the current proposed syntax, it is sufficient for the pre-processor to strip out everything between angle brackets after the protocol name to produce a backward-compatible declaration. A minimal implementation of such a pre-processor is a simple sed invocation, like `sed -e 's/\(protocol .*\)<.*> {/\1 {/'`.
+
+### Generic protocols
+
+This proposal uses the angle-bracket syntax for constraining primary associated types, instead of a hypothetical "generic protocols" feature modeled after Haskell's multi-parameter typeclasses or Rust's generic traits. The idea is that such a "generic protocol" can be parametrized over multiple types, not just a single `Self` conforming type:
+
+```swift
+protocol ConvertibleTo {
+ static func convert(_: Self) -> Other
+}
+
+extension String : ConvertibleTo {
+ static func convert(_: String) -> Int
+}
+
+extension String : ConvertibleTo {
+ static func convert(_: String) -> Double
+}
+```
+
+We believe that constraining primary associated types is a more generally useful feature than generic protocols, and using angle-bracket syntax for constraining primary associated types gives users what they generally expect, with the clear analogy between `Array` and `Collection`.
+
+Nothing in this proposal precludes introducing generic protocols in the future under a different syntax, perhaps something that does not privilege the `Self` type over other types to make it clear there is no functional dependency between the type parameters like there is with associated types:
+
+```swift
+protocol Convertible(from: Self, to: Other) {
+ static func convert(_: Self) -> Other
+}
+
+extension Convertible(from: String, to: Int) {
+ static func convert(_: String) -> Int
+}
+
+extension Convertible(from: String, to: Double) {
+ static func convert(_: String) -> Double
+}
+```
+
+## Source compatibility
+
+This proposal does not impact source compatibility for existing code.
+
+Adding a primary associated type list to an existing protocol is a source-compatible change.
+
+The following are **source-breaking** changes:
+
+- Removing the primary associated type list from an existing protocol.
+- Changing the order or contents of a primary associated type list of an existing protocol.
+
+## Effect on ABI stability
+
+This proposal does not impact ABI stability for existing code. The new feature does not require runtime support and can be backward-deployed to existing Swift runtimes.
+
+The primary associated type list is not part of the ABI, so all of the following are binary-compatible changes:
+
+- Adding a primary associated type list to an existing protocol.
+- Removing the primary associated type list from a existing protocol.
+- Changing the primary associated type list of an existing protocol.
+
+The last two are source-breaking however, so are not recommended.
+
+## Effect on API resilience
+
+This change does not impact API resilience for existing code.
+
+## Future Directions
+
+### Standard library adoption
+
+Actually adopting primary associated types in the standard library is outside of the scope of this proposal. There are the obvious candidates such as `Sequence` and `Collection`, and no doubt others that will require additional discussion.
+
+### Constrained existentials
+
+As stated above, this proposal alone does not enable constrained protocol existential types, such as `any Collection`.
+
+## Acknowledgments
+
+Thank you to Joe Groff for writing out the original vision for improving generics ergonomics — which included the initial idea for this feature — and to Alejandro Alonso for implementing the lightweight same-type constraint syntax for extensions on generic types which prompted us to think about this feature again for protocols.
diff --git a/proposals/0347-type-inference-from-default-exprs.md b/proposals/0347-type-inference-from-default-exprs.md
new file mode 100644
index 0000000000..db105e1d92
--- /dev/null
+++ b/proposals/0347-type-inference-from-default-exprs.md
@@ -0,0 +1,264 @@
+# Type inference from default expressions
+
+* Proposal: [SE-0347](0347-type-inference-from-default-exprs.md)
+* Authors: [Pavel Yaskevich](https://github.com/xedin)
+* Review Manager: [Doug Gregor](https://github.com/DougGregor)
+* Status: **Implemented (Swift 5.7)**
+* Decision Notes: [Rationale](https://forums.swift.org/t/accepted-se-0347-type-inference-from-default-expressions/56558)
+* Implementation: [apple/swift#41436](https://github.com/apple/swift/pull/41436)
+
+## Introduction
+
+It's currently impossible to use a default value expression with a generic parameter type to default the argument and its type:
+
+```swift
+func compute(_ values: C = [0, 1, 2]) { ❌
+ ...
+}
+```
+
+An attempt to compile this declaration results in the following compiler error - `default argument value of type '[Int]' cannot be converted to type 'C'` because, under the current semantic rules, the type of a default expression has to work for every possible concrete type replacement of `C` inferred at a call site. There are couple of ways to work around this expressivity limitation, but all of them require overloading which complicates APIs:
+
+```
+func compute(_ values: C) { // original declaration without default
+ ...
+}
+
+func compute(_ values: [Int] = [0, 1, 2]) { // concretely typed overload of `compute` with default value
+ ...
+}
+```
+
+I propose to allow type inference for generic parameters from concretely-typed default parameter values (referred to as default expressions in the proposal) when the call-site omits an explicit argument. Concretely-typed default expressions would still be rejected by the compiler if generic parameters associated with a defaulted parameter could be inferred _at a call site_ from any other location in a parameter list by an implicit or explicit argument. For example, declaration `func compute(_: T = 42, _: U) where U: Collection, U.Element == T` is going to be rejected by the compiler because it's possible to infer a type of `T` from the second argument, but declaration `func compute(_: T = 42, _: U = []) where U: Collection, U.Element == Int` is going to be accepted because `T` and `U` are independent.
+
+Under the proposed rules, the original `compute` declaration becomes well formed and doesn't require any additional overloads:
+
+```swift
+func compute(_ values: C = [0, 1, 2]) { ✅
+ ...
+}
+```
+
+Swift-evolution thread: [Discussion thread topic for that proposal](https://forums.swift.org/t/pitch-type-inference-from-default-expressions/55585)
+
+
+## Motivation
+
+Interaction between generic parameters and default expressions is confusing when default expression only works for a concrete specialization of a generic parameter. It's possible to spell it in the language (in some circumstances) but requires boiler-plate code and knowledge about nuances of constrained extensions.
+
+For example, let's define a `Flags` protocol and a container type for default set of flags:
+
+```swift
+protocol Flags {
+ ...
+}
+
+struct DefaultFlags : Flags {
+ ...
+}
+```
+
+Now, let's declare a type that accepts a set of flags to act upon during initialization.
+
+```swift
+struct Box {
+ init(dimensions: ..., flags: F) {
+ ...
+ }
+}
+```
+
+
+To create a `Box` , the caller would have to pass an instance of type conforming to `Flags` to its initializer call. If the majority of `Box`es doesn’t require any special flags, this makes for subpar API experience, because although there is a `DefaultFlags` type, it’s not currently possible to provide a concretely typed default value for the `flags` parameter, e.g. (`flags: F = DefaultFlags()`). Attempting to do so results in the following error:
+
+```
+error: default argument value of type 'DefaultFlags' cannot be converted to type 'F'
+```
+
+This happens because even though `DefaultFlags` does conform to protocol `Flags` the default value cannot be used for _every possible_ `F` that can be inferred at a call site, only when `F` is `DefaultFlags`.
+
+To avoid having to pass flags, it's possible to "specialize" the initializer over a concrete type of `F` via combination of conditional extension and overloading.
+
+Let’s start with a direct `where` clause:
+
+```swift
+struct Box {
+ init(dimensions: ..., flags: F = DefaultFlags()) where F == DefaultFlags {
+ ...
+ }
+}
+```
+
+This `init` declaration results in a loss of memberwise initializers for `Box`.
+
+Another possibility is a constrained extension which makes `F` concrete `DefaultFlags` like so:
+
+```swift
+extension Box where F == DefaultFlags {
+ init(dimensions: ..., flags: F = DefaultFlags()) {
+ ...
+ }
+}
+```
+
+Initialization of `Box` without `flags:` is now well-formed and implicit memberwise initializers are preserved, albeit with `init` now being overloaded, but this approach doesn’t work in situations where generic parameters belong to the member itself.
+
+Let’s consider that there is an operation on our `Box` type that requires passing a different set of flags:
+
+```swift
+extension Box {
+ func ship(_ flags: F) {
+ ...
+ }
+}
+```
+
+
+The aforementioned approach that employs constrained extension doesn’t work in this case because generic parameter `F` is associated with the method `ship` instead of the `Box` type. There is another trick that works in this case - overloading.
+
+ New method would have to have a concrete type for `flags:` like so:
+
+```swift
+extension Box {
+ func ship(_ flags: DefaultShippingFlags = DefaultShippingFlags()) {
+ ...
+ }
+}
+```
+
+This is a usability pitfall - what works for some generic parameters, doesn’t work for others, depending on whether the parameter is declared. This inconsistency sometimes leads to API authors reaching for existential types, potentially without realizing all of the consequences that might entail, because a declaration like this would be accepted by the compiler:
+
+```swift
+extension Box {
+ func ship(_ flags: any Flags = DefaultShippingFlags()) {
+ ...
+ }
+}
+```
+
+ Also, there is no other way to associate default value `flags:` parameter without using existential types for enum declarations:
+
+```swift
+enum Box {
+}
+
+extension Box where F == DefaultFlags {
+ case flatRate(dimensions: ..., flags: F = DefaultFlags()) ❌ // error: enum 'case' is not allowed outside of an enum
+}
+```
+
+
+To summarize, there is a expressivity limitation related to default expressions which could be, only in some circumstances, mitigated via constrained extensions feature, its other issues include:
+
+1. Doesn’t work for generic parameters associated with function, subscript, or case declarations because constrained extensions could only be declared for types i.e. `init(..., flags: F = F()) where F == DefaultFlags` is not allowed.
+2. Methods have to be overloaded, which increases API surface of the `Box` , and creates a matrix of overloads if there are more than combination of parameters with default values required i.e. if `dimensions` parameter was to be made generic and defaulted for some box sides.
+3. Doesn’t work for `enum` declarations at all because Swift does not support overloading cases or declaring them in extensions.
+4. Requires know-how related to constrained extensions and their ability to bind generic parameters to concrete types.
+
+## Proposed solution
+
+To address the aforementioned short-comings of the language, I propose to support a more concise and intuitive syntax - to allow concretely typed default expressions to be associated with parameters that refer to generic parameters.
+
+```swift
+struct Box {
+ init(flags: F = DefaultFlags()) {
+ ...
+ }
+}
+
+Box() // F is inferred to be DefaultFlags
+Box(flags: CustomFlags()) // F is inferred to be CustomFlags
+```
+
+This syntax could be achieved by amending the type-checking semantics associated with default expressions to allow type inference from them at call sites in cases where such inference doesn’t interfere with explicitly passed arguments.
+
+## Detailed design
+
+Type inference from default expressions would be allowed if:
+
+1. The generic parameter represents either a direct type of a parameter i.e. `(_: T = ...)` or used in a nested position i.e. `(_: [T?] = ...)`
+2. The generic parameter is used only in a single location in the parameter list. For example, `(_: T, _: T = ...)` or `(_: [T]?, _: T? = ...)` are *not* allowed because only an explicit argument is permitted to resolve a type conflict to avoid any surprising behavior related to implicit joining of the types.
+ 1. Note: A result type is allowed to reference generic parameter types inferable from default expressions to make it possible to use the feature while declaring initializers of generic types or `case`s of generic enums.
+3. There are no same-type generic constraints that relate a generic parameter that could be inferred from a default expression with any other parameter that couldn’t be inferred from the same expression. For example, `(_: T = [...], _: U) where T.Element == U` is not allowed because `U` is not associated with defaulted parameter where `T` is used, but `(_: [(K, V?)] = ...) where K.Element == V` is permitted because both generic parameters are associated with one expression.
+4. The default expression produces a type that satisfies all of the conformance, layout and other generic requirements placed on each generic parameter it would be used to infer at a call site.
+
+
+With these semantic updates, both the initializer and `ship` method of the `Box` type could be expressed in a concise and easily understandable way that doesn’t require any constrained extensions or overloading:
+
+```swift
+struct Box {
+ init(dimensions: ..., flags: F = DefaultFlags()) {
+ ...
+ }
+
+ func ship(_ flags: F = DefaultShippingFlags()) {
+ ...
+ }
+}
+```
+
+`Box` could also be converted to an enum without any loss of expressivity:
+
+```swift
+enum Box {
+case flatRate(dimensions: D = [...], flags: F = DefaultFlags())
+case overnight(dimensions: D = [...], flags: F = DefaultFlags())
+...
+}
+```
+
+At the call site, if the defaulted parameter doesn’t have an argument, the type-checker will form an argument conversion constraint from the default expression type to the parameter type, which guarantees that all of the generic parameter types are always inferred.
+
+```swift
+let myBox = Box(dimensions: ...) // F is inferred as DefaultFlags
+
+myBox.ship() // F is inferred as DefaultShippingFlags
+```
+
+Note that it is important to establish association between the type of a default expression and a corresponding parameter type not just for inference sake, but to guarantee that there are not generic parameter type clashes with a result type (which is allowed to mention the same generic parameters):
+
+```swift
+func compute(initialValues: T = [0, 1, 2, 3]) -> T {
+ // A complex computation that uses initial values
+}
+
+let result: Array = compute() ✅
+// Ok both `initialValues` and result type are the same type - `Array`
+
+let result: Array = compute() ❌
+// This is an error because type of default expression is `Array` and result
+// type is `Array`
+```
+
+## Source compatibility
+
+Proposed changes to default expression handling do not break source compatibility.
+
+
+## Effect on ABI stability
+
+No ABI impact since this is an additive change to the type-checker.
+
+
+## Effect on API resilience
+
+All of the resilience rules associated with adding and removing of default expressions are left unchanged, see https://github.com/apple/swift/blob/main/docs/LibraryEvolution.rst#id12 for more details.
+
+
+## Alternatives considered
+
+[Default generic arguments](https://github.com/apple/swift/blob/main/docs/GenericsManifesto.md#default-generic-arguments) feature mentioned in the Generics Manifesto should not be confused with type inference rules proposed here. Having an ability to default generic arguments alone is not enough to provide a consistent way to use default expressions when generic parameters are involved. The type inference described in this proposal would still be necessary allow default expressions with concrete type to be used when the parameter references a type parameter, and to determine whether the default expression works with a default generic argument type, which means that default generic arguments feature could be considered an enhancement instead of an alternative approach.
+
+A number of similar approaches has been discussed on Swift Forums, one of them being [[Pre-pitch] Conditional default arguments - #4 by Douglas_Gregor - Dis...](https://forums.swift.org/t/pre-pitch-conditional-default-arguments/7122/4) which relies on overloading, constrained extensions, and/or custom attributes and therefore has all of the issues outlined in the Motivation section. Allowing type inference from default expressions in this regard is a much cleaner approach that works for all situations without having to introduce any new syntax or custom attributes.
+
+
+## Future Directions
+
+This proposal limits use of inferable generic parameters to a single location in a parameter list because all default expressions are type-checked independently. It is possible to lift this restriction and type-check all of the default expressions together which means that if generic parameters is inferable from different default expressions its type is going to be a common type that fits all locations (action of obtaining such a type is called type-join). It’s not immediately clear whether lifting this restriction would always adhere to the principle of the least surprise for the users, so it would require a separate discussion if this proposal is accepted.
+
+The simplest example that illustrates the problem is `test(a: T = 42, b: T = 4.2)-> T` , this declaration creates a matrix of possible calls each of which could be typed differently:
+
+1. `test()` — T = Double because the only type that fits both `42` and `4.2` is `Double`
+2. `test(a: 0.0)` — T = `Double`
+3. `test(b: 0)` — T = `Int`
+4. `let _: Int = test()` - fails because `T` cannot be `Int` and `Double` at the same time.
diff --git a/proposals/0348-buildpartialblock.md b/proposals/0348-buildpartialblock.md
new file mode 100644
index 0000000000..4a196e68c6
--- /dev/null
+++ b/proposals/0348-buildpartialblock.md
@@ -0,0 +1,306 @@
+# `buildPartialBlock` for result builders
+
+* Proposal: [SE-0348](0348-buildpartialblock.md)
+* Author: [Richard Wei](https://github.com/rxwei)
+* Implementation: [apple/swift#41576](https://github.com/apple/swift/pull/41576)
+* Review Manager: [Ben Cohen](https://github.com/airspeedswift)
+* Status: **Implemented (Swift 5.7)**
+
+## Overview
+
+We introduce a new result builder customization point that allows components of a block to be combined pairwise.
+
+```swift
+@resultBuilder
+enum Builder {
+ /// Builds a partial result component from the first component.
+ static func buildPartialBlock(first: Component) -> Component
+
+ /// Builds a partial result component by combining an accumulated component
+ /// and a new component.
+ /// - Parameter accumulated: A component representing the accumulated result
+ /// thus far.
+ /// - Parameter next: A component representing the next component after the
+ /// accumulated ones in the block.
+ static func buildPartialBlock(accumulated: Component, next: Component) -> Component
+}
+```
+
+When `buildPartialBlock(first:)` and `buildPartialBlock(accumulated:next:)` are both provided, the [result builder transform](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0289-result-builders.md#the-result-builder-transform) will transform components in a block into a series of calls to `buildPartialBlock`, combining one subsequent line into the result at a time.
+
+```swift
+// Original
+{
+ expr1
+ expr2
+ expr3
+}
+
+// Transformed
+// Note: `buildFinalResult` and `buildExpression` are called only when they are defined, just like how they behave today.
+{
+ let e1 = Builder.buildExpression(expr1)
+ let e2 = Builder.buildExpression(expr2)
+ let e3 = Builder.buildExpression(expr3)
+ let v1 = Builder.buildPartialBlock(first: e1)
+ let v2 = Builder.buildPartialBlock(accumulated: v1, next: e2)
+ let v3 = Builder.buildPartialBlock(accumulated: v2, next: e3)
+ return Builder.buildFinalResult(v3)
+}
+```
+
+The primary goal of this feature is to reduce the code bloat caused by overloading `buildBlock` for multiple arities, allowing libraries to define builder-based generic DSLs with joy and ease.
+
+## Motivation
+
+Among DSLs powered by result builders, it is a common pattern to combine values with generic types in a block to produce a new type that contains the generic parameters of the components. For example, [`ViewBuilder`](https://developer.apple.com/documentation/swiftui/viewbuilder) and [`SceneBuilder`](https://developer.apple.com/documentation/swiftui/scenebuilder) in SwiftUI use `buildBlock` to combine views and scenes without losing strong types.
+
+```swift
+extension SceneBuilder {
+ static func buildBlock(Content) -> Content
+ static func buildBlock(_ c0: C0, _ c1: C1) -> some Scene where C0: Scene, C1: Scene
+ ...
+ static func buildBlock(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4, _ c5: C5, _ c6: C6, _ c7: C7, _ c8: C8, _ c9: C9) -> some Scene where C0: Scene, C1: Scene, C2: Scene, C3: Scene, C4: Scene, C5: Scene, C6: Scene, C7: Scene, C8: Scene, C9: Scene
+}
+```
+
+Due to the lack of variadic generics, `buildBlock` needs to be overloaded for any supported block arity. This unfortunately increases code size, causes significant code bloat in the implementation and documentation, and it is often painful to write and maintain the boiletplate.
+
+While this approach works for types like `ViewBuilder` and `SceneBuilder`, some builders need to define type combination rules that are far too complex to implement with overloads. One such example is [`RegexComponentBuilder`](https://github.com/apple/swift-experimental-string-processing/blob/85c7d906dd871364357156126278d9d427936ca4/Sources/_StringProcessing/RegexDSL/Builder.swift#L13) in [Declarative String Processing](https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/DeclarativeStringProcessing.md).
+
+The regex builder DSL is designed to allow developers to easily compose regex patterns. [Strongly typed captures](https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/StronglyTypedCaptures.md#strongly-typed-regex-captures) are represented as part of the `Match` generic parameter in the `Regex` type, which has a builder-based initializer.
+
+```swift
+struct Regex {
+ init(@RegexComponentBuilder _ builder: () -> Self)
+}
+```
+
+> #### Recap: Regular expression capturing basics
+>
+> When a regular expression does not contain any capturing groups, its `Match` type is `Substring`, which represents the whole matched portion of the input.
+>
+> ```swift
+> let noCaptures = #/a/# // => Regex
+> ```
+>
+> When a regular expression contains capturing groups, i.e. `(...)`, the `Match` type is extended as a tuple to also contain *capture types*. Capture types are tuple elements after the first element.
+>
+> ```swift
+> // ________________________________
+> // .0 | .0 |
+> // ____________________ _________
+> let yesCaptures = #/a(?:(b+)c(d+))+e(f)?/# // => Regex<(Substring, Substring, Substring, Substring?)>
+> // ---- ---- --- --------- --------- ----------
+> // .1 | .2 | .3 | .1 | .2 | .3 |
+> // | | | | | |
+> // | | |_______________________________ | ______ | ________|
+> // | | | |
+> // | |______________________________________ | ______ |
+> // | |
+> // |_____________________________________________|
+> // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+> // Capture types
+> ```
+
+Using the result builder syntax, the regular expression above becomes:
+
+```swift
+let regex = Regex {
+ "a" // => Regex
+ OneOrMore { // {
+ Capture { OneOrMore("b") } // => Regex<(Substring, Substring)>
+ "c" // => Regex
+ Capture { OneOrMore("d") } // => Regex<(Substring, Substring)>
+ } // } => Regex<(Substring, Substring, Substring)>
+ "e" // => Regex
+ Optionally { Capture("f") } // => Regex<(Substring, Substring?)>
+} // => Regex<(Substring, Substring, Substring, Substring?)>
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // Capture types
+
+let result = "abbcddbbcddef".firstMatch(of: regex)
+// => MatchResult<(Substring, Substring, Substring, Substring?)>
+```
+
+`RegexComponentBuilder` concatenates the capture types of all components as a flat tuple, forming a new `Regex` whose `Match` type is `(Substring, CaptureType...)`. We can define the following `RegexComponentBuilder`:
+
+```swift
+@resultBuilder
+enum RegexComponentBuilder {
+ static func buildBlock() -> Regex
+ static func buildBlock(_: Regex) -> Regex
+ // Overloads for non-tuples:
+ static func buildBlock(_: Regex