Contents

Migrating away from experimental suppressed associated types (OldSuppressedAssociatedTypes)

0503 Suppressed Associated Types officially introduced the ability to define protocols with associated types that are ~Copyable and/or ~Escapable (i.e., “suppressed”), which relaxes the requirement on types conforming to that protocol. During the evolution process, a prototype version of this feature existed under the experimental feature named SuppressedAssociatedTypes. That experimental feature is now deprecated and is source-incompatible with the accepted version detailed in SE-503.

Overview

This document provides high-level guidance for users of this experimental feature to help them update their code to be compatible with SE-503. Please see the evolution proposal for complete details of the accepted functionality.

Source Changes

Primary associated types are those that are mentioned within angle brackets of a protocol:

protocol Mailbox<Items> {
  //            ^~~~~~~ declares that `Items` is a primary associated type
  
  associatedtype Items: ~Copyable
  associatedtype Generator: ~Copyable
  
  // ...
}

Relative to the prototype, SE-503 infers default requirements for primary associated types in places they were not already. The defaults are expanded within extensions of the protocol:

extension Mailbox {} // OLD
extension Mailbox where Items: ~Copyable {} // NEW

The defaults are also expanded in generic contexts where a conformance requirement involving that protocol is written. So, to preserve existing behavior, you’ll need add explicit suppressions on the associated types induced by those conformance requirements within those contexts:

func foo<T>(..) where T: Mailbox {} // OLD
func foo<T>(..) where T: Mailbox, T.Items: ~Copyable {} // NEW

struct PostOffice<M: Mailbox> {} // OLD
struct PostOffice<M: Mailbox> where M.Items: ~Copyable {} // NEW

ABI Changes

The implementation of SE-503 changes the mangling scheme for generic signatures as a result of the inferred defaults. Suppose you have this protocol:

protocol Drink<Flavor> {
  associatedtype Flavor: ~Copyable
}

and these two functions that are completely explicit about whether T.Flavor is Copyable or not:

func foo<T: Drink>(_ t: T) where T.Flavor: Copyable {}
func bar<T: Drink>(_ t: T) where T.Flavor: ~Copyable {}

In the prototype version of the feature, bar’s requirement T.Flavor: ~Copyable was redundant, whereas foo’s requirement T.Flavor: Copyable was not redundant, so it would be included in the mangled symbol of foo:

$s1X3fooyyxAA5DrinkRzs8Copyable6FlavorRpzlF ---> X.foo<A where A: X.Drink, A.Flavor: Swift.Copyable>(A) -> ()
$s1X3baryyxAA5DrinkRzlF ---> X.bar<A where A: X.Drink>(A) -> ()

With SE-503, this almost flips around. It’s now foo whose requirement is redundant, and bar’s mangled symbol now mentions the requirement T.Flavor: ~Copyable:

$s1X3fooyyxAA5DrinkRzlF ---> X.foo<A where A: X.Drink>(A) -> ()
$s1X3baryyxAA5DrinkRz6FlavorRj_zlF ---> X.bar<A where A: X.Drink, A.Flavor: ~Swift.Copyable>(A) -> ()

It’s possible to preserve the old symbol for bar by using @abi to produce its symbol as if T.Flavor: Copyable:

// $s1X3baryyxAA5DrinkRzlF ---> X.bar<A where A: X.Drink>(A) -> ()
@abi(func bar<T: Drink>(_ t: T) where T.Flavor: Copyable)
func bar<T: Drink>(_ t: T) where T.Flavor: ~Copyable {}

But, only brittle internal compiler features can be used preserve foo’s old mangled symbol $s1X3fooyyxAA5DrinkRzs8Copyable6FlavorRpzlF.

See Also