Strange error in a generic initializer

So I have a struct with the following declaration.

public struct Rational<IntegerType : UnsignedInteger & FixedWidthInteger> {
    public let numerator: IntegerType
    
    public let denominator: IntegerType

    internal init(_ numerator: IntegerType,
                  _ denominator: IntegerType,
                  reduce: Bool = false) {
        /// Implementation...
    }
}

This initializer gives me the following error:
Cannot convert value of type 'T.Magnitude' to expected argument type 'IntegerType'.

public init<T : BinaryInteger>(_ numerator: T,
                               _ denominator: T)
where IntegerType == T.Magnitude {
    self.init(numerator.magnitude,
              denominator.magnitude,
              reduce: true)
}

It seems to be ignoring the where clause entirely.

Out of curiosity—and I don't believe this should make a difference—what happens if you reverse the equality and express the constraint as where T.Magnitude == IntegerType?

Nothing changes.

I got to test this out and I'm seeing the same behavior in a SwiftFiddle with Swift 5.6.2. What does work is creating IntegerTypes out of the given magnitudes, but this shouldn't be necessary:

public init<T: BinaryInteger>(_ numerator: T, _ denominator: T) where T.Magnitude == IntegerType {
    self.init(IntegerType(numerator.magnitude),
              IntegerType(denominator.magnitude),
              reduce: true)
}

This looks like a bug to me, which would be worth reporting.

1 Like

The new generics implementation that ships with 5.7 should fix this (download a snapshot to confirm).

2 Likes