An initializer specialized for conformance wasn't suggested/present

I have a sequence to do arithmetic progressions:

public struct ArithmeticallyProgressingSequence<Element: AdditiveArithmetic>: LazySequenceProtocol {
    public let distance: Element
    public let start: Element

    @inlinable
    public init(start: Element, distance: Element) {
        self.start = start
        self.distance = distance
    }

    public struct Iterator: IteratorProtocol {
        public let distance: Element
        @usableFromInline
        var upcoming: Element

        @inlinable
        init(start: Element, distance: Element) {
            upcoming = start
            self.distance = distance
        }

        @inlinable
        public mutating func next() -> Element? {
            defer { upcoming += distance }

            return upcoming
        }
    }

    @inlinable
    public __consuming func makeIterator() -> Iterator {
        return Iterator(start: start, distance: distance)
    }
}

with a specialty initializer when the Element is also Numeric:

extension ArithmeticallyProgressingSequence where Element: Numeric {
    @inlinable
    public init(factor: Element, startingMultiple: Element, offset: Element = 0) {
        precondition(offset.magnitude < factor.magnitude)

        self.init(start: factor * startingMultiple + offset, distance: factor)
    }
}

but when I used the type in a client where the iterated variable was an integer type that conformed to BinaryInteger, only the primary initializer was suggested. Since BinaryInteger refines Numeric, which refines AdditiveArithmetic, I should have gotten both initializers as options. In fact, writing in the secondary initializer's labels makes the compiler suggest a fix-it to change the labels back to the primary initializer's. Why isn't the compiler recognizing my element type qualifies for both initializers?

The lines from the client:

    else {
        // The error with the second initializer: "Incorrect argument labels in call (have 'factor:startingMultiple:', expected 'start:distance:')"
        // Fix-it: "Replace 'factor: upcoming * upcoming, startingMultiple' with 'start: upcoming * upcoming, distance'"
        primeMultiples.append(Advancer(factor: upcoming * upcoming, startingMultiple: upcoming))
        return true
    }

where upcoming is of type Integer, which is the generic argument:

struct MyType<Integer: BinaryInteger> { /*...*/ }

Never mind, I messed up.

The project above is from an Xcode framework. I originally wrote it in a Playground.

  • I wrote the iterator type first.
  • I had both initializers in the iterator
  • Then I wrote the wrapping sequence type, with both initializers
  • The new edition keeps both initializers for the sequence, but drops the secondary one for the iterator since it's fully contained in the sequence, and the sequence strips the source material which would make the secondary initializer work for the iterator.
  • The Advancer type in the sample is the iterator.

So I revised to:

primeMultiples.append(APSequence(factor: upcoming, startingMultiple: upcoming).makeIterator())

Sorry.

Terms of Service

Privacy Policy

Cookie Policy