mirror of
https://github.com/apple/swift.git
synced 2026-02-27 18:26:24 +01:00
This change forces you to write ``@reparented` relationships
on an extension of a protocol, rather than on the protocol
itself.
The ProtocolConformance needs to be associated with some
GenericContext and IRGen expects it to be an ExtensionDecl.
That environment defines under what conditions the conformance
exists. We also need to define witnesses for the new parent's
requirements in an extension anyway, so it's a natural fit.
The previous workaround for this was kind of awful, as it'd
require searching all the protocol's extensions and "guess"
which extension they want to represent the conformance. While
we could try to synthesize an extension, there's two
challenges there:
1. Due to SuppressedAssociatedTypes, it's not so simple to
synthesize an unconstrained ExtensionDecl.
2. We currently rely on same-type requirements to pin the
associated types to particular witnesses of those requirements
in the extension. So it's not purely unconstrained! For example,
```
extension Seq: @reparented BorrowSeq where Iter == MyIter {}
```
The constraints that are disallowed (but not yet diagnosed)
are conditional conformance requirements, as the default
conformance for a reparenting cannot depend on those.
Thus, it's better that programmers to specify the extension.
102 lines
1.9 KiB
Swift
102 lines
1.9 KiB
Swift
public func libraryVersion() -> Int {
|
|
#if BEFORE
|
|
return 0
|
|
#else
|
|
return 10
|
|
#endif
|
|
}
|
|
|
|
#if BEFORE
|
|
|
|
public protocol Bird {
|
|
func eat(_ food: Int) -> Int
|
|
}
|
|
|
|
#else
|
|
|
|
@reparentable
|
|
public protocol SeedEater {
|
|
func eatSeed(_ food: Int) -> Int
|
|
|
|
associatedtype Kind: AsInt
|
|
|
|
var seedKinds: Kind { get }
|
|
}
|
|
|
|
public protocol Bird {
|
|
func eat(_ food: Int) -> Int
|
|
}
|
|
|
|
extension Bird : @reparented SeedEater where Kind == Int {
|
|
public func eatSeed(_ food: Int) -> Int { return eat(food + libraryVersion()) }
|
|
|
|
public var seedKinds: Int {
|
|
get { return libraryVersion() }
|
|
}
|
|
}
|
|
|
|
public protocol AsInt {
|
|
func asInt() -> Int
|
|
}
|
|
|
|
extension Int: AsInt {
|
|
public func asInt() -> Int { return self }
|
|
}
|
|
|
|
#endif
|
|
|
|
public struct SomeType {
|
|
public static func feed(_ b: some Bird, _ clientVersion: Int) -> Int {
|
|
#if BEFORE
|
|
return b.eat(clientVersion)
|
|
#else
|
|
let ans1 = asBase(b).eatSeed(clientVersion)
|
|
let ans2 = feedAsBase_Param(b, clientVersion)
|
|
precondition(ans1 == ans2)
|
|
return ans1
|
|
#endif
|
|
}
|
|
|
|
public static func count(_ b: some Bird, _ clientVersion: Int) -> Int {
|
|
#if BEFORE
|
|
return clientVersion
|
|
#else
|
|
return clientVersion + asBase(b).seedKinds.asInt()
|
|
#endif
|
|
}
|
|
|
|
#if !BEFORE
|
|
private static func asBase(_ b: some Bird) -> some SeedEater { return b }
|
|
|
|
private static func feedAsBase_Param(_ se: some SeedEater, _ food: Int) -> Int {
|
|
return se.eatSeed(food)
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
public struct ExistentialType {
|
|
public static func feed(_ b: any Bird, _ clientVersion: Int) -> Int {
|
|
#if BEFORE
|
|
return b.eat(clientVersion)
|
|
#else
|
|
return asExtBase(b).eatSeed(clientVersion)
|
|
#endif
|
|
}
|
|
|
|
public static func count(_ b: some Bird, _ clientVersion: Int) -> Int {
|
|
#if BEFORE
|
|
return clientVersion
|
|
#else
|
|
return clientVersion + asExtBase(b).seedKinds.asInt()
|
|
#endif
|
|
}
|
|
|
|
#if !BEFORE
|
|
private static func asExtBase(_ b: any Bird) -> any SeedEater { return b }
|
|
#endif
|
|
}
|
|
|
|
|