I first commented out the Collection
conformance
extension LazyDeduplicationSequence/*: Collection*/ where Base: Collection {
And the Collection
members themselves gave no error. Then I wondered if adding the conformance at the same time as the members was the problem. I first diverted myself with the backwards code:
extension LazyDeduplicationSequence/*: BidirectionalCollection*/ where Base: BidirectionalCollection {
public func index(before i: Index) -> Index {
let previousEnd = i.isoRange.lowerBound
let previousLast = base.index(before: previousEnd) // Crashes here if at startIndex
let previousValue = base[previousLast]
let previousStart: Base.Index
if let doublePreviousLast = base[...previousLast].lastIndex(where: { !areEquivalent($0, previousValue) }) {
previousStart = base.index(after: doublePreviousLast)
} else {
previousStart = base.startIndex
}
return Index(previousStart..<previousEnd)
}
}
Then added conformance in separated statements:
extension LazyDeduplicationSequence: Collection where Base: Collection {}
extension LazyDeduplicationSequence: LazyCollectionProtocol where Base: Collection {}
extension LazyDeduplicationSequence: BidirectionalCollection where Base: BidirectionalCollection {}
But the same error for the Collection
block showed up. But the BidirectionalCollection
error had a fix-it attached. When I opened it, it asked to provide stubs. To my surprise, the stub wasn't a dummy Index
type-alias, but a dummy Indices
type-alias.
Could the default definition of Indices
been the problem? I re-read "Indices.swift," where DefaultIndices
lives, but I didn't see a problem. Then I made up my own indices-bundle type:
public struct LazyDeduplicationIndices<Elements: Collection> where Elements.SubSequence == Elements {
@usableFromInline
let elements: LazyDeduplicationCollection<Elements>
@inlinable
init(_ base: LazyDeduplicationCollection<Elements>) {
elements = base
}
}
extension LazyDeduplicationIndices: Collection {
@inlinable
public var underestimatedCount: Int { return elements.underestimatedCount }
public struct Index: Comparable {
@usableFromInline
let isoRange: Range<Elements.Index>
@inlinable
init(_ base: Range<Elements.Index>) {
isoRange = base
}
@inlinable
public static func < (lhs: Index, rhs: Index) -> Bool {
return lhs.isoRange.lowerBound < rhs.isoRange.lowerBound
}
}
@inlinable
public var startIndex: Index { return elements.startIndex }
@inlinable
public var endIndex: Index { return elements.endIndex }
@inlinable
public subscript(position: Index) -> Index {
return position
}
@inlinable
public subscript(bounds: Range<Index>) -> LazyDeduplicationIndices {
return LazyDeduplicationIndices(elements[bounds])
}
@inlinable
public var indices: LazyDeduplicationIndices { return self }
@inlinable
public var isEmpty: Bool { return elements.isEmpty }
@inlinable
public func index(after i: Index) -> Index {
return elements.index(after: i)
}
}
extension LazyDeduplicationIndices.Index: Hashable where Elements.Index: Hashable {}
extension LazyDeduplicationIndices: BidirectionalCollection where Elements: BidirectionalCollection {
@inlinable
public func index(before i: Index) -> Index {
return elements.index(before: i)
}
}
Since I didn't erase the collection code in LazyDeduplicationSequence
, I could re-use it, even though the sequence type itself doesn't (yet) conditionally conform to Collection
. I added a custom indices
member to the extension then uncommented the Collection
-conformance statement, and... it worked! Or at least didn't trigger a pre-compilation error. Uncommenting the LazyCollectionProtocol
and BidirectionalCollection
statements worked too, and the project worked when I did a full unit-test.
Why did supplying a custom Indices
work? Is there a bug in the pre-checker in that it didn't tell me what was wrong in Collection
conformance? I only got it due to trying BidirectionalCollection
conformance and that's what BC suggested I fill in a stub for.