Files
swift-mirror/validation-test/Evolution/Inputs/protocol_add_reparented_seq.swift
Kavon Farvardin 006a0a494a Reparenting: require an extension
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.
2026-02-03 16:40:21 -08:00

99 lines
2.5 KiB
Swift

public protocol BorrowingIter<Element>: ~Copyable, ~Escapable {
associatedtype Element: ~Copyable
// NOTE: Span has availability that blocks us from testing it here
mutating func nextThing() -> Element?
}
public protocol Iterable {
associatedtype Element
mutating func next() -> Element?
}
public struct LibraryLegacyIter: Iterable {
public typealias Element = String
public func next() -> String? { return "LibraryLegacyIter" }
}
public struct LibraryConformer: Seq {
public typealias Element = String
public typealias Iterator = LibraryLegacyIter
public func makeIterator() -> Iterator {
print("LibraryConformer.makeIterator()")
return Iterator()
}
}
#if BEFORE
public protocol Seq<Element> {
associatedtype Element
associatedtype Iterator: Iterable
func makeIterator() -> Iterator
}
#else
public protocol Seq<Element> {
associatedtype Element
associatedtype Iterator: Iterable
func makeIterator() -> Iterator
associatedtype BorrowingSeqIter: BorrowingIter<Element>, ~Copyable, ~Escapable = Adapter<Iterator>
}
@reparentable
public protocol BorrowingSeq<Element>: ~Copyable, ~Escapable {
associatedtype Element: ~Copyable
associatedtype BorrowingSeqIter: BorrowingIter<Element>, ~Copyable, ~Escapable
@_lifetime(borrow self)
func makeBorrowingSeqIter() -> BorrowingSeqIter
}
extension Seq : @reparented BorrowingSeq
where BorrowingSeqIter == Adapter<Iterator> {
public func makeBorrowingSeqIter() -> BorrowingSeqIter {
return Adapter(makeIterator())
}
}
public struct Adapter<Iterator: Iterable>: BorrowingIter {
public typealias Element = Iterator.Element
var iterator: Iterator
public init(_ iterator: Iterator) { self.iterator = iterator }
public mutating func nextThing() -> Element? {
print("Adapter invoking iterator.next()")
return iterator.next()!
}
}
public struct LibraryNewIter: BorrowingIter {
public func nextThing() -> String? {
return "LibraryNewIter"
}
}
extension LibraryConformer {
public typealias BorrowingSeqIter = LibraryNewIter
public func makeBorrowingSeqIter() -> BorrowingSeqIter {
print("LibraryConformer.makeBorrowingSeqIter()")
return BorrowingSeqIter()
}
}
#endif
public func libraryTest(_ x: some Seq) {
var iter = x.makeIterator()
print(iter.next()!)
#if !BEFORE
libraryTestNew(x)
#endif
}
#if !BEFORE
public func libraryTestNew(_ x: some BorrowingSeq) {
var borrowingIter = x.makeBorrowingSeqIter()
let answer = borrowingIter.nextThing()!
print(answer)
}
#endif