Why can't I use my generic type's operator * when the type conforms to FloatingPoint?

I'm trying to make pointfree's generic struct Tagged conditionally conform to FloatingPoint and I'm running into a problem: when I try to use (for example) operator * on my type, I get an ambiguous use of operator '*' error.

To simplify the problem, I stripped out the generic Tag parameter, leaving just the RawValue parameter. Here's the type definition and a bunch of conditional conformances, all the way to FloatingPoint. Sorry it's so long but I couldn't find anything else that I could remove while still conforming to FloatingPoint.

struct GenericWrapper<RawValue> {
    var rawValue: RawValue
    init(_ value: RawValue) { rawValue = value }
}

func combined<RawValue>(_ a: GenericWrapper<RawValue>, _ b: GenericWrapper<RawValue>, using combiner: (RawValue, RawValue) throws -> RawValue) rethrows -> GenericWrapper<RawValue> {
    return GenericWrapper<RawValue>.init(try combiner(a.rawValue, b.rawValue))
}

func formCombination<RawValue>(_ a: inout GenericWrapper<RawValue>, _ b: GenericWrapper<RawValue>, using combiner: (RawValue, RawValue) throws -> RawValue) rethrows {
    a = try combined(a, b, using: combiner)
}

extension GenericWrapper: Equatable where RawValue: Equatable { }
extension GenericWrapper: Hashable where RawValue: Hashable { }

extension GenericWrapper: Comparable where RawValue: Comparable {
    static func <(_ a: GenericWrapper, _ b: GenericWrapper) -> Bool {  return a.rawValue < b.rawValue }
}

extension GenericWrapper: ExpressibleByFloatLiteral where RawValue: ExpressibleByFloatLiteral {
    typealias FloatLiteralType = RawValue.FloatLiteralType
    init(floatLiteral: FloatLiteralType) { self.init(RawValue(floatLiteral: floatLiteral)) }
}

extension GenericWrapper: ExpressibleByIntegerLiteral where RawValue: ExpressibleByIntegerLiteral {
    typealias IntegerLiteralType = RawValue.IntegerLiteralType
    init(integerLiteral: IntegerLiteralType) { self.init(RawValue(integerLiteral: integerLiteral)) }
}

extension GenericWrapper: Numeric where RawValue: Numeric {
    typealias Magnitude = GenericWrapper<RawValue.Magnitude>
    init?<T>(exactly source: T) where T : BinaryInteger {
        guard let value = RawValue(exactly: source) else { return nil }
        self.init(value)
    }
    var magnitude: Magnitude { return Magnitude.init(rawValue.magnitude) }
    static func +(_ a: GenericWrapper, _ b: GenericWrapper) -> GenericWrapper { return combined(a, b, using: +) }
    static func +=(_ a: inout GenericWrapper, _ b: GenericWrapper) { formCombination(&a, b, using: +) }
    static func -(_ a: GenericWrapper, _ b: GenericWrapper) -> GenericWrapper { return combined(a, b, using: -) }
    static func -=(_ a: inout GenericWrapper, _ b: GenericWrapper) { formCombination(&a, b, using: -) }
    static func *(_ a: GenericWrapper, _ b: GenericWrapper) -> GenericWrapper { return combined(a, b, using: *) }
    static func *=(_ a: inout GenericWrapper, _ b: GenericWrapper) { formCombination(&a, b, using: *) }
}

extension GenericWrapper: SignedNumeric where RawValue: SignedNumeric { }

extension GenericWrapper: Strideable where RawValue: Strideable {
    typealias Stride = GenericWrapper<RawValue.Stride>
    func distance(to other: GenericWrapper<RawValue>) -> Stride { return GenericWrapper<RawValue.Stride>.init(rawValue.distance(to: other.rawValue)) }
    func advanced(by n: Stride) -> GenericWrapper<RawValue> { return GenericWrapper<RawValue>.init(rawValue.advanced(by: n.rawValue)) }
}

extension GenericWrapper: FloatingPoint where RawValue: FloatingPoint {
    typealias Exponent = RawValue.Exponent

    init(sign: FloatingPointSign, exponent: Exponent, significand: GenericWrapper) { self.init(RawValue.init(sign: sign, exponent: exponent, significand: significand.rawValue)) }
    init(signOf signDonor: GenericWrapper, magnitudeOf magnitudeDonor: GenericWrapper) { self.init(RawValue(signOf: signDonor.rawValue, magnitudeOf: magnitudeDonor.rawValue)) }

    init(_ value: UInt8) { self.init(RawValue(value)) }
    init(_ value: Int8) { self.init(RawValue(value)) }
    init(_ value: UInt16) { self.init(RawValue(value)) }
    init(_ value: Int16) { self.init(RawValue(value)) }
    init(_ value: UInt32) { self.init(RawValue(value)) }
    init(_ value: Int32) { self.init(RawValue(value)) }
    init(_ value: UInt64) { self.init(RawValue(value)) }
    init(_ value: Int64) { self.init(RawValue(value)) }
    init(_ value: UInt) { self.init(RawValue(value)) }
    init(_ value: Int) { self.init(RawValue(value)) }
    init<Source>(_ value: Source) where Source : BinaryInteger { self.init(RawValue(value)) }

    static var radix: Int { return RawValue.radix }
    static var nan: GenericWrapper { return GenericWrapper<RawValue>.init(RawValue.nan) }
    static var signalingNaN: GenericWrapper { return GenericWrapper<RawValue>.init(RawValue.signalingNaN) }
    static var infinity: GenericWrapper { return GenericWrapper<RawValue>.init(RawValue.infinity) }
    static var greatestFiniteMagnitude: GenericWrapper { return GenericWrapper<RawValue>.init(RawValue.greatestFiniteMagnitude) }
    static var pi: GenericWrapper { return GenericWrapper<RawValue>.init(RawValue.pi) }
    var ulp: GenericWrapper { return GenericWrapper<RawValue>.init(rawValue.ulp) }
    static var leastNormalMagnitude: GenericWrapper { return GenericWrapper<RawValue>.init(RawValue.leastNormalMagnitude) }
    static var leastNonzeroMagnitude: GenericWrapper { return GenericWrapper<RawValue>.init(RawValue.leastNonzeroMagnitude) }
    var sign: FloatingPointSign { return rawValue.sign }
    var exponent: RawValue.Exponent { return rawValue.exponent }
    var significand: GenericWrapper { return GenericWrapper<RawValue>.init(rawValue.significand) }
    static func / (lhs: GenericWrapper, rhs: GenericWrapper) -> GenericWrapper { return combined(lhs, rhs, using: /) }
    static func /= (lhs: inout GenericWrapper, rhs: GenericWrapper) { lhs.rawValue /= rhs.rawValue }
    mutating func formRemainder(dividingBy other: GenericWrapper) { rawValue.formRemainder(dividingBy: other.rawValue) }
    mutating func formTruncatingRemainder(dividingBy other: GenericWrapper) { rawValue.formTruncatingRemainder(dividingBy: other.rawValue) }
    mutating func formSquareRoot() { rawValue.formSquareRoot() }
    mutating func addProduct(_ lhs: GenericWrapper, _ rhs: GenericWrapper) { rawValue.addProduct(lhs.rawValue, rhs.rawValue) }
    var nextUp: GenericWrapper { return GenericWrapper<RawValue>.init(rawValue.nextUp) }
    func isEqual(to other: GenericWrapper) -> Bool { return rawValue.isEqual(to: other.rawValue) }
    func isLess(than other: GenericWrapper) -> Bool { return rawValue.isLess(than: other.rawValue) }
    func isLessThanOrEqualTo(_ other: GenericWrapper) -> Bool { return rawValue.isLessThanOrEqualTo(other.rawValue) }
    func isTotallyOrdered(belowOrEqualTo other: GenericWrapper) -> Bool { return rawValue.isTotallyOrdered(belowOrEqualTo: other.rawValue) }
    var isNormal: Bool { return rawValue.isNormal }
    var isFinite: Bool { return rawValue.isFinite }
    var isZero: Bool { return rawValue.isZero }
    var isSubnormal: Bool { return rawValue.isSubnormal }
    var isInfinite: Bool { return rawValue.isFinite }
    var isNaN: Bool { return rawValue.isNaN }
    var isSignalingNaN: Bool { return rawValue.isSignalingNaN }
    var isCanonical: Bool { return rawValue.isCanonical }

    mutating func round(_ rule: FloatingPointRoundingRule) { rawValue.round(rule) }
}

So then I want to use the type like this:

typealias DataValue = GenericWrapper<Double>

let d0: DataValue = 10
let d1: DataValue = 12

print(d0 * d1) // error: ambiguous use of operator '*'

But compilation fails:

:; /Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2018-08-14-a.xctoolchain/usr/bin/swiftc -c main.swift 
main.swift:113:14: error: ambiguous use of operator '*'
    print(d0 * d1)
             ^
main.swift:43:21: note: found this candidate
        static func *(_ a: GenericWrapper, _ b: GenericWrapper) -> GenericWrapper { return combined(a, b, using: *) }
                    ^
Swift.FloatingPoint:36:24: note: found this candidate
    public static func * (lhs: Self, rhs: Self) -> Self
                       ^
Swift.Numeric:9:24: note: found this candidate
    public static func * (lhs: Self, rhs: Self) -> Self

The first candidate is my definition of * for GenericWrapper. The other two appear to just point at the protocol requirements. I searched the Swift standard library source code and couldn't find any actual method definitions for * on Numeric or FloatingPoint.

Incidentally, the Swift.Numeric candidate is new to the master branch. The swift-4.2-DEVELOPMENT-SNAPSHOT-2018-08-14-a.xctoolchain doesn't print that candidate, but does print the Swift.FloatingPoint candidate.

Note that the follow tests compile and run successfully:

func f<T: FloatingPoint>(_ a: T, _ b: T) -> T {
    return a * b
}

print(f(d0, d1))

let g: (DataValue, DataValue) -> DataValue = f
print(g(d0, d1))

So here are my questions:

  • What, if any, is the bug in my code that's causing the “ambiguous operator” error?

  • If it's not a bug in my code, is there a workaround to make d0 * d1 compile?

Looks like a bug to me!

That's a bug, and I am pretty sure @Slava_Pestov is aware about this one. It's not the first time it shows up on the forum.

Here's a reduced example. The compiler treats the restated operator function requirement in B as a candidate, which renders an ambiguity. You can fix the error by deleting one of the commented lines (or both).

protocol A {
    static func * (lhs: Self, rhs: Self) -> Self
}

protocol B: A {
//    static func * (lhs: Self, rhs: Self) -> Self
    func foo()
}

struct S: B {
    static func * (lhs: S, rhs: S) -> S { return lhs }
    func foo() {}
}

struct D<T> {}

extension D: A where T: A {
    static func * (lhs: D, rhs: D) -> D { return lhs }
}

// extension D: B where T: B { func foo() {} }

let y = D<S>() * D<S>()