Contents

SE-0503: Suppressed Default Conformances on Associated Types With Defaults

* Proposal: [SE-0503](0503-suppressed-associated-types.md) * Authors: [Kavon Farvardin](https://github.com/kavon) * Review Manager: [Ben Cohen](https://github.com/airspeedswift) * Status: **Accepted** * Implementation: on `main` using `-enable-experimental-feature SuppressedAssociatedTypesWithDefaults` * Previous Proposals: [SE-0427: Noncopyable Generics](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0427-noncopyable-generics.md), [SE-0446: Nonescapable Types](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0446-non-escapable.md) * Review: ([pitch](https://forums.swift.org/t/pitch-suppressed-associated-types-with-defaults/83663)) ([review](https://forums.swift.org/t/se-0503-suppressed-default-conformances-on-associated-types-with-defaults/84070))

Introduction

An associated type defines a generic type in a protocol. You use them to help define the protocol's requirements. This Queue has two associated types, Element and Allocator:

/// Queue has no reason to require Element to be Copyable.
protocol Queue<Element>: ~Copyable {
  associatedtype Element
  associatedtype Allocator = DefaultAllocator

  init()
  init(alloc: Allocator)

  mutating func push(_: Element)
  mutating func pop() -> Element
  // ...
}

The first associated type Element represents the type of value by which push and pop must be defined.

Any type conforming to Queue must define a nested type Element that satisfies (or witnesses) the protocol's requirements for its Element. This nested type could be a generic parameter named Element, a typealias named Element, and so on. While the type conforming to Queue is permitted to be noncopyable, its Element type has to be Copyable:

/// error: LinkedList does not conform to Queue
/// note: Element is required to be Copyable
struct LinkedList<Element: ~Copyable>: ~Copyable, Queue {
  ...
}

This is because in SE-427: Noncopyable Generics, an implicit requirement that Queue.Element is both Copyable and Escapable is inferred, with no way to suppress it. This is an expressivity limitation in practice, as it prevents Swift programmers from defining protocols in terms of noncopyable or nonescapable associated types.

Proposed Solution

The existing syntax for suppressing these default conformances is extended to associated type declarations:

/// Correct Queue protocol.
protocol Queue<Element>: ~Copyable {
  associatedtype Element: ~Copyable
  associatedtype Allocator: ~Copyable = DefaultAllocator

  init()
  init(alloc: consuming Allocator)

  mutating func push(_: consuming Self.Element)
  mutating func pop() -> Self.Element
}

Now, LinkedList can conform to Queue, as its Element is not required to be Copyable. The associated type Allocator is also not required to be Copyable, meaning the DefaultAllocator, which is used when the conformer doesn't define its own Allocator, can be either Copyable or not. Similarly, stating ~Escapable is allowed, to suppress the default conformance requirement for Escapable. Unless otherwise noted, any discussion of ~Copyable types applies equivalently to ~Escapable types in this proposal.

Defaulting Behavior

Swift's philosophy behind defaulting generic parameters to be Copyable (and Escapable) is rooted in the idea that programmers expect their types to have that ability. Library authors choosing to generalize their design with support for ~Copyable generics will not impose a burden of annotation on the common user, because Swift will default their extensions and generic parameters to still be Copyable. This idea serves as the foundation of the proposed defaulting behavior for associated types.

Here is a simplistic protocol for a Buffer that imposes no Copyable requirements:

protocol Buffer<Data>: ~Copyable {
  associatedtype Data: ~Copyable
  associatedtype Parser: ~Copyable
  ...
}

Recall the existing rules from SE-427: Noncopyable Generics. Under those rules, a protocol extension of Buffer always introduces a default Self: Copyable requirement, since the protocol itself doesn't require it.

By this proposal, default conformance requirements will also be introduced if any of a protocol's primary associated types (those appearing in angle brackets) are suppressed. For Buffer, that means only a default Data: Copyable is introduced, not one for the ordinary (non-primary) associated type Parser, when constraining the generic parameter B to conform to Buffer:

// by default,  B: Copyable, B.Data: Copyable
func read<B: Buffer>(_ bytes: [B.Data], into: B) { ... }

Unlike a primary associated type, an ordinary associated type is not typically used generically by conformers. This rationale is in line with the original reason there is a distinction among associated types from SE-346:

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.

The type Buffer is an example of this, as users often will build utilities that deal with the Data generically, not Parser. Consider these example conformers,

struct BinaryParser: ~Copyable { ... }
struct TextParser { ... }

class DecompressingReader<Data>: Buffer {
  typealias Parser = BinaryParser
}

struct Reader<Data>: Buffer {
  typealias Parser = TextParser
}

// by default,  Self.Copyable, Self.Data: Copyable
extension Buffer {
  // `valid` is provided for both DecompressingReader and Reader
  func valid(_ bytes: [UInt8]) -> Bool { ... }
}

If ordinary associated types like Buffer.Parser were to default to Copyable, then the extension of Buffer adding a valid method would exclude conformers that witnessed the Parser with a noncopyable type, despite that being an implementation detail.

Detailed Design

There are three ways to impose a requirement on an associated type:
- In the inheritance clause of the associated type declaration.
- In a `where` clause attached to the associated type declaration.
- In a `where` clause attached to the protocol itself.

This proposal extends the **Detailed Design** section of
[SE-427: Noncopyable Generics](0427-noncopyable-generics.md) to allow
suppressing default conformance to Copyable in Escapable in all of
the above positions. Thus, all three below are equivalent:
```swift
protocol P { associatedtype A: ~Copyable }
protocol P { associatedtype A where Self.A: ~Copyable }
protocol P where Self.A: ~Copyable { associatedtype A }
```

### Expansion Procedure

While building the [generic signature](https://download.swift.org/docs/assets/generics.pdf) 
for a declaration, such as a generic function or type, the expansion procedure adds 
infers extra requirements based on the desugared requirements of that declaration.
The procedure itself is simple,

> Suppose there is a protocol `P` that declares primary associated types `A1, ..., An`. 
> If there exists a desugared requirement `Subject: P`, the procedure infers 
> the extra requirements `Subject.A1: IP, ..., Subject.An: IP`, for each invertible
> protocol `IP ∈ {Copyable, Escapable}`.
> If there exists a validly scoped inverse requirement `Subject.A1: ~IP`, then 
> that cancels out the inferred requirement `Subject.A1: IP`, for any invertible 
> protocol IP.

As in [SE-427: Noncopyable Generics](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0427-noncopyable-generics.md), 
after building the declaration's generic signature, if there was an inverse
requirement `Thing: ~IP` and yet Thing must conform to IP anyway, then the 
inverse requirement is diagnosed as invalid.

### Limits of Suppression

Default requirements become fixed once the generic signature is built for that
declaration, after applying the expansion procedure. For example,

```swift
protocol Pushable<Element> {
  associatedtype Element: ~Copyable
}

struct Stack<Scope: Pushable> {}

func push<Val>(_ s: Stack<Val>, _ v: Val) 
  where Val.Element: ~Copyable // error
  {}
```

When the generic signature of Stack is built, the expansion procedure adds
the requirement `Scope.Element: Copyable`, because of the requirement
`Scope: Pushable` and Element being a primary associated type. The minimized
generic signature of Stack becomes,

```
<Scope where Scope : Pushable, Scope.[Pushable]Element : Copyable>
```

When building the generic signature of `push`, requirement inference consults 
the generic signature of Stack, adding the hard requirements that 
`Val == Scope` and `Scope.Element: Copyable`. There is no way to satisfy the
inverse requirement `Val.Element: ~Copyable` without mutating the generic 
signature of Stack, which is not permitted, so the inverse requirement is 
illegally scoped in `push`.

The same concept applies to the requirement signatures of a protocol becoming
fixed after expansion is applied to it locally. Consider this protocol `P`,

```swift
protocol P<A>: ~Copyable { 
  associatedtype A: ~Copyable
}
```

Its requirement signature is `<Self where Self : Escapable, Self.A : Escapable>`,
because the default Copyable requirements were suppressed on both Self and
`Self.A`. Next, consider this protocol `Q`,

```swift
protocol Q<B>: ~Copyable { 
  associatedtype B: ~Copyable, P
}
```

The expansion procedure applies locally to `Q` as follows. 
The desugared requirement `Self.B: P` implies `Self.B.A: Copyable`, yielding the now-fixed requirement signature:

```
<Self where Self : Escapable, Self.B : P, Self.B.A : Copyable>
                                          ~~~~~~~~~~~~~~~~~~~
                                          from expansion procedure
```

Constraining a generic type parameter `T` to conform to `Q` only permits suppression of a default inferred for `T.B`, not `T.B.A`:

```swift
func limits<T: Q>(_ t: T) 
  where T.B: ~Copyable, 
        T.B.A: ~Copyable // error: T.B.A is required to be Copyable
        {}
```

Inverses can apply across equality constraints _within the same declaration's generic signature_
to cancel-out default requirements from primary associated types. Consider this example,

```swift
protocol Iterable<Element>: ~Copyable {
  associatedtype Element: ~Copyable
}

struct Cursor<Value>: Iterable<Value> where Value: ~Copyable {}
```

In Cursor, the inheritance clause contains `Iterable<Value>` yielding the 
desugared requirements `Element: Copyable` and `Element == Value`.
There is also an inverse requirement `Value: ~Copyable` within Cursor 
that cancels-out the default requirement `Element: Copyable` inferred from 
the conformance to Iterable. Thus, the inverse requirement is well-scoped.

### Protocol inheritance

Defaulting interacts with protocol inheritance as follows. If a base protocol
declares an associated type with a suppressed conformance, this
associated type will also have a suppressed conformance in the derived
protocol, unless either of the following are true:

 1. it is a primary associated type in the base protocol
 2. the derived protocol re-states the associated type

Here are some examples,
```swift
protocol Base<A> {
  associatedtype A: ~Copyable
  associatedtype B: ~Copyable
}

// Case 1: 'A' requires Copyable because it's a primary associated type in Base
protocol Derived1: Base {
  // 'A' is Copyable
  // 'B' is ~Copyable
}

// Case 2, Restating the associated type B infers fresh defaults for it.
protocol Derived2: Base {
  // 'A' is Copyable
  // 'B' is Copyable
  associatedtype B
}
```

It is possible to suppress the default coming from a base protocol via Case 1 
using an inverse requirement:

```swift
// Derived3 suppresses the default from Case 1.
protocol Derived3: Base where Self.A: ~Copyable {
  // 'A' is ~Copyable
  // 'B' is ~Copyable
}
```

Elevating an ordinary associated type from a base protocol to a primary 
associated type (such as in Child) will not infer a default within that
particular protocol,

```swift
protocol Child<B>: Base {
  // 'A' is Copyable
  // 'B' is ~Copyable
}
```

But that elevation it will infer defaults in protocols downstream of it,
such as in Grandchild:

```swift
// Case 1: Child.B is a primary associated type
protocol Grandchild: Child {
  // 'A' is Copyable
  // 'B' is Copyable
}
```

It is illegal to suppress the Copyable requirements
on `A` or `B` in a protocol derived from Grandchild, as they become fixed
in the Grandchild protocol:

```swift
protocol GrandGrandchild: Grandchild {
  // 'A' is Copyable
  // 'B' is Copyable
}
```

Case 1 does not apply in GrandGrandchild to permit suppression
on 'A' or 'B' coming from Grandchild. It is the same situation as this:

```swift
protocol Bird {
  associatedtype Song
}

protocol Eagle: Bird where Self.Song: ~Copyable {}
```

where Bird declares a Song that is an associated type with a fixed Copyable
requirement; it not suppressed and not defaulted in Eagle via Case 1.

### Extensions

Consider this simple protocol for iteration,

```swift
protocol Iterable<Element>: ~Copyable {
  associatedtype Element: ~Copyable
  ...
}
```

An extension of Iterable introduces a default for Element because it is
a primary associated type, which is suppressible:

```swift
// implicitly,  where Self: Copyable, Self.Element: Copyable
extension Iterable {}

// implicitly,  where Self: Copyable
extension Iterable where Element: ~Copyable {}

// fully without defaults
extension Iterable where Self: ~Copyable, Element: ~Copyable {}
```

For ordinary associated types like Strategy in the next example, 
no default is inferred,

```swift
protocol PersistedDictionary<Key, Value>: ~Copyable {
  associatedtype Key: ~Copyable
  associatedtype Value: ~Copyable
  associatedtype Strategy: ~Copyable
}

// implicitly,  where Self: Copyable, Self.Key: Copyable, Self.Value: Copyable
extension PersistedDictionary {}
```

An inverse requirement in an extension of a protocol that conflicts with the
protocol's requirement signature is invalid,

```swift
protocol Viewable<Element>: Iterable {}

extension Viewable where Element: ~Copyable {}
// ^ error: 'Self.Element' required to be 'Copyable' but is marked with '~Copyable'
```

Viewable's requirement signature includes `Self.Element: Copyable` from
its inheritance of Iterable, which has its Element as a primary associated 
type. Once that becomes fixed in Viewable's signature, extensions of it cannot
remove the Copyable requirement. The inverse requirement must be stated on
Viewable itself to suppress the default requirement from Iterable.

### Existentials

Suppose we have the protocol,

```swift
protocol Source<Element>: ~Copyable {
  associatedtype Element: ~Copyable
  associatedtype Generator: ~Copyable
  
  func element() -> Element
  func generator() -> Generator
}
```

Existentials such as `any P` work similarly to the case of a single generic 
parameter `T`  has a conformance requirement `T: P`. The expansion of
defaults happens here as well,

```swift
func ex1(_ s: any Source) {
  let e = s.element()   // <- Copyable
  let g = s.generator() // <- NOT Copyable
}
```

It's possible to constrain the existential using a generic type parameter,
which will suppress the defaults expansion for the primary associated type of
Source,

```swift
func ex2<R: ~Copyable>(_ s: any Source<R>) {
  let e = s.element()   // <- NOT Copyable
  let g = s.generator() // <- NOT Copyable
}
```

### Recursion

There can be an infinite number of type parameters derivable from a conformance
requirement, because a protocol's associated type requirement can be part of a cycle with the protocol itself:

```swift
protocol P<A>: ~Copyable {
  associatedtype A: ~Copyable, P
}
```

For a generic signature `<R where R: P>`, all of the type parameters 
`R.A, R.A.A, R.A.A.A, ...`,
are Copyable. 
For any type parameter `X` rooted in `R`, the type `X.A` conforms to `P`, and by the expansion procedure, that implies `X.A: Copyable` because `A` is a primary
associated type of `P`.

Next, consider this pair of mutually recursive protocols where only one of 
them has a primary associated type,

```swift
protocol First<A>: ~Copyable {
  associatedtype A: ~Copyable, Second
}

protocol Second: ~Copyable {
  associatedtype B: ~Copyable, First
}
```

For a generic signature `<T where T: First>`, we observe that any type parameter
rooted in T and ending with an A, such T.A.B.A, is Copyable because 
`T.A.B: First` and First has a primary associated type A. 
Similarly, for type parameter T.A.B which ends in a B, it is *not* required to conform to Copyable, because `T.A: Second` and Second has only
the ordinary associated type B. So there is an alternating pattern for the 
defaults,

```
T.A : Copyable
T.A.B: ~Copyable
T.A.B.A: Copyable
T.A.B.A.B: ~Copyable
...
```

### Default Witnesses

An associated type can already declare a default _witness_, which is a type that
is used to witness an associated type requirement, if the conforming type does
not specify one. For example, in SegmentedArray's conformance to Queue, it 
doesn't declare a nested type named Allocator satisfying the requirements of
`Queue.Allocator`, so it automatically uses DefaultAllocator:
```swift
protocol Queue<Element>: ~Copyable {
  associatedtype Element: ~Copyable
  associatedtype Allocator: Alloc & ~Copyable = DefaultAllocator
  ...
  `init(alloc: consuming Allocator)`
}
protocol Alloc: ~Copyable { ... }
struct DefaultAllocator: Alloc { ... }
```
The DefaultAllocator conforms to Copyable, which is simple for conformers
when implementing the rest of Queue's requirements:
```swift
struct SegmentedArray<Element>: Queue { 
  // uses DefaultAllocator by default
  init(alloc: DefaultAllocator)
}
```
By the defaulting rules in this proposal, a generic type parameter `Q` 
constrained to Queue will *not* assume `Q.Allocator` is Copyable, since it is
an ordinary associated type:
```swift
// by default,  Q.Element: Copyable
func createSubQueues<Q: Queue>(_ kind: Q.Type, 
                               n: Int, 
                               with alloc: borrowing Q.Allocator) -> [Q] {
  // Q.Allocator is ~Copyable
}
```
Thus, even if the default witness for a suppressed associated type conforms to
Copyable and/or Escapable, matching generic requirement(s) *are not*
introduced. 

> **Rationale:** Part of the reason for this is understandability, as it's 
> possible for the default witness to have a conditional conformance for
> Copyable or Escapable. For example,
> 
> ```swift
> struct ForwardIterator<Item: ~Copyable>: ~Copyable { ... }
> extension ForwardIterator: Copyable where Item: Copyable { ... }
> 
> protocol Iterable<Element> {
>   associatedtype Element: ~Copyable
>   associatedtype Iter: ~Copyable = ForwardIterator<Element>
>   
>   func getIter() -> Iter
> }
> ```
> The default witness for `Iterable.Iter` is ForwardIterator, which is only
> Copyable if the Element is Copyable. Thus, the default constraints for 
> Iter would vary depending on the Element type in these functions:
> 
> ```swift
> func runForwardsInt(_ it: some Iterable<Int>) {
>   _ = copy it.getIter() // OK
> }
> 
> func runForwardsNC(_ it: some Iterable<NonCopyableType>) {
>   _ = copy it.getIter() // error: copy of noncopyable type
> }
> ```
> The same goes for extensions of the protocol.


### Library evolution and new associated type requirements

Protocols are allowed to introduce new requirements, including associated type
requirements, without breaking source or binary compatibility, as long
as a default implementation is provided for existing code.

Suppose a new primary associated type is introduced that is `~Copyable` and
the default witness does not conform to Copyable:

```swift
protocol Foo<New> {
  // Added in v2
  associatedtype New: ~Copyable
}

struct NC: ~Copyable {}

// Added in v2
extension Foo where New: ~Copyable { typealias New = NC }
```

Because of the defaulting behavior of primary associated type to Copyable, 
and the choice of providing a noncopyable default witness, this can change
the meaning of source code when it compiles against the new definition of the 
protocol:

```swift
struct ExistingConformance: Foo {}

// `T: Foo` implies `T.New: Copyable` after recompiling against Foo v2...
func existingFunction<T: Foo>(_: T) {}

func existingCaller() {
  // ...then this previously-working line of code would stop compiling, because
  // ExistingConformance.New defaults to noncopyable type NC, so doesn't
  // satisfy the default `T.New: Copyable` requirement.
  existingFunction(ExistingConformance())
}
```

Thus, the default witness must be carefully chosen to avoid a source break.

### Conditional conformance

Finally, recall that concrete types may conform to Copyable and
Escapable conditionally, depending on the copyability or
escapability of a generic parameter. Even though associated types
may now suppress conformance to these protocols, a conditional
conformance to Copyable or Escapable that depends on an
associated type is still not allowed:
```swift
protocol Goose: ~Copyable { associatedtype Quack: ~Copyable }
struct Pond<G: Goose>: ~Copyable {}
extension QueueHolder: Copyable where G.Quack: Copyable {}  // error
```
This restriction is for runtime implementation limitations.

<!-- TODO: Perhaps the limitation needs elaboration? -->

Source Compatibility

The introduction of this feature in the language does not break any existing code, because any usage of the suppressed conformance syntax with associated types was diagnosed as an error.

One of the goals of this proposal is to make it safe to suppress a conformance on an existing primary associated type. A protocol's set of primary associated types can’t be added to or removed once declared without breaking source compatibility.

Changing an existing ordinary associated type declaration to suppress conformance to Copyable or Escapable is also a source-breaking change. For example, if a library publishes this protocol:

public protocol Manager: ~Copyable {
  associatedtype Resource
}

Client code that states a T: Manager requirement on a generic parameter T can then assume that the type parameter T.Resource is Copyable:

extension Manager where Self: ~Copyable {
  func makeCopies(_ r: Self.Resource) -> (Self.Resource, Self.Resource) {
    return (r, r)
  }
}

Now suppose the library author then changes the protocol to suppress conformance:

public protocol Manager: ~Copyable {
  associatedtype Resource: ~Copyable
}

The client's extension of Manager will no longer type check, because the body of makeCopies() assumes r is Copyable, and this assumption is no longer true.

ABI Compatibility

The ABI of existing code is not affected by this proposal.

On the other hand, changing an associated type declaration in an library to suppress conformance is can be an ABI-breaking change. For example, an extension of a protocol providing a default implementation could have its symbol name change, as these two implementations of greet must have distinct names:

protocol Greeter<T> {
  associatedtype T: ~Copyable
  func greet()
}

extension Greeter {
  func greet() { print("hello")}
}

extension Greeter where T: ~Copyable {
  func greet() { print("سلام") }
}

Future Directions

It's possible to imagine additional functionality that could one day be supported, but is not part of this proposal.

Constrained Existentials via some

There is some support for constrained existentials, such as

func f<T: Hashable>(_ e: any P<T>) {}

It might be a generally useful feature if there were support for a syntax such as any P<some Hashable> to permit the constrained existential to carry with it the constraint that its primary associated type conforms to Hashable. That syntax could then be extended to allow suppression of defaults in the constrained existential via any Q<some ~Copyable>.

Alternatives Considered

Through the development of this proposal, various alternate formulations were considered.

No defaulting

A prior version of this proposal was pitched that was absent of any defaulting behavior for associated types. The primary fault was that it provided an inconsistent behavior when compared with generic types like S:

struct S<T: ~Copyable>: ~Copyable {}

protocol P<T>: ~Copyable {
  associatedtype T: ~Copyable
}

extension S {} // T: Copyable
extension P {} // T: ~Copyable

Only the extension for S provides a default for its T.

Definition-driven associated type defaults

Rather than try to impose a blanket default on all primary associated types, we might instead apply a limited defaulting rule only to select associated types, driven by some aspect of the protocol definition. This could come at the expense of increased language complexity. Readers would have to carefully consult the definitions of protocols to see whether they come with default Copyable or Escapable requirements on their associated types.

Some possibilities for how this might look include:

Protocol-defined default requirements

We could let a protocol definition dictate any set of Copyable or Escapable requirements to get imposed by default when used as a generic requirement. This set of requirements would have to be finite.

protocol Container: ~Copyable, ~Escapable {
    associatedtype BorrowingIterator: BorrowingIteratorProtocol,
      ~Copyable, ~Escapable
    associatedtype Element: ~Copyable, ~Escapable  

    default Element: Copyable, Element: Escapable
}

// defaults to 'where Element: Copyable & Escapable' only.
//
// Self and Self.BorrowingIterator remain ~Copyable & ~Escapable
extension Container {}

This might also serve as a way for a protocol to opt generic parameters out of defaulting to Copyable and/or Escapable when the protocol is used as a constraint, which may be desirable for protocols that are only used with noncopyable or nonescapable conformers in practice.

Default constraint sets

There may be more than one local optimum set of default requirements for a protocol. An elaboration of the protocol-defined defaults idea might be to allow multiple, named sets of constraints, which can be individually suppressed as a group. For instance, this would make it possible to provide configurations of a protocol to suppress copying and escaping individually, without making developers write out the entire set of constraint suppressions:

protocol Container: ~Copyable, ~Escapable {
    associatedtype BorrowingIterator: BorrowingIteratorProtocol,
      ~Copyable, ~Escapable
    associatedtype Element: ~Copyable, ~Escapable  
    
    default constraintset Copying where Self: Copyable, Self.Element: Copyable
    default constraintset Escaping where Self: Escapable, Self.Element: Escapable
}

// implicitly has the 'Copying' & 'Escaping' sets of requirements
extension Container {}

extension Container without Copying {} // some inbetween kind
extension Container without Escaping {} 

extension Container without Copying, Escaping {} // fully unconstrained in -version

func f<T: Container>() without T: Container.Copying {}

// We could have syntax that allows you to refer to constraintsets like a member,
// to opt out a generic type parameter from multiple constrainsets:
func g<T: Container & P>() without T: Container.Copying or T: P.Copying {}

This functionality might also be used for future evolution. Let’s say we add a third suppressable protocol Runcible in the future, and we want to generalize Container to allow for ~Runcible elements. We can suppress the Runcible requirement on Self and Self.Element along with a new default constraint set that reinstates the requirements for existing code. Existing code would continue to apply all of the default sets, and doesn’t know about the new constraint set yet, so would not suppress the newly lifted requirements:

protocol Container: ~Copyable, ~Escapable, ~Runcible {
                                         // ^ added in v2

    associatedtype BorrowingIterator: BorrowingIteratorProtocol,
      ~Copyable, ~Escapable
    associatedtype Element: ~Copyable, ~Escapable, ~Runcible
                                                // ^ added in v2:
      
      
    associatedtype SubContainer: Container /*implies where SubContainer: C,E,R*/
    
    default constraintset Copying where Self: Copyable, Self.Element: Copyable
    default constraintset Escaping where Self: Escapable, Self.Element: Escapable
    // added in v2 to maintain compatibility:
    default constraintset Runcing where Self: Runcible, Self.Element: Runcible
}

// These all retain their meaning from v1:
extension Container {}
extension Container without Copying {}
extension Container without Escaping {} 
extension Container without Copying, Escaping {}

// In v2, code can now do the following for maximum permissivity:
extension Container without Copying, Escaping, Runcing {}

Acknowledgements

I'd like to thank the following people for their discussion, insights and/or contributions throughout the development of this proposal: