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 {} // NEWThe 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 {} // NEWABI 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
@dynamicCallable implementation requirements (DynamicCallable)Add @preconcurrency import (AddPreconcurrencyImport)Always enabled availability domains (AlwaysAvailableDomain)Argument matching for trailing closures (TrailingClosureMatching)Calling a mutating async actor-isolated method (ActorIsolatedMutatingAsync)Calling an actor-isolated method from a synchronous nonisolated context (ActorIsolatedCall)Captures in a `@Sendable` closure (SendableClosureCaptures)Compilation caching (CompilationCaching)Conforming to `StringInterpolationProtocol` (StringInterpolationConformance)Conversion from `@isolated(any)` function type to synchronous function type (ConversionFromIsolatedAnyToSynchronous)Cross-isolation data race (RegionIsolationCrossIsolationDataRace)Deprecated declaration warnings (DeprecatedDeclaration)Deprecated implementation-only imports (ImplementationOnlyDeprecated)Dynamic exclusivity (DynamicExclusivity)Embedded Swift language restrictions (EmbeddedRestrictions)