# “Ambiguous” operators when conditionally conforming to Numeric

I just got hit by a weird “ambiguous operator” error. It came up with a generic type which does not conform to `Numeric`, but nonetheless implements all the operators for it. Then, in a conditional extension, I added the conformance. Unfortunately, the operators cannot actually be *used* in the conditional extension, because of an alleged ambiguity.

I’ve cut it down to a small example. In this stripped-down version, there are ways to work around the issue, such as making the conformance unconditional. However in the actual place I encountered it, the conformance must be conditional.

• • •

``````struct Foo<T: Numeric> : Equatable {
var x: T
}

extension Foo : ExpressibleByIntegerLiteral {
init(integerLiteral value: T.IntegerLiteralType) {
x = T(integerLiteral: value)
}
}
``````

Give it some basic operators:

``````extension Foo {
static func += (lhs: inout Foo, rhs: Foo) { lhs.x += rhs.x }
static func -= (lhs: inout Foo, rhs: Foo) { lhs.x -= rhs.x }
static func *= (lhs: inout Foo, rhs: Foo) { lhs.x *= rhs.x }

static func + (lhs: Foo, rhs: Foo) -> Foo {
var result = lhs
result += rhs
return result
}

static func - (lhs: Foo, rhs: Foo) -> Foo {
var result = lhs
result -= rhs
return result
}

static func * (lhs: Foo, rhs: Foo) -> Foo {
var result = lhs
result *= rhs
return result
}
}
``````

And add a conditional conformance to `Numeric`:

``````extension Foo : Numeric where T : FloatingPoint {
typealias Magnitude = T.Magnitude

var magnitude: T.Magnitude { return x.magnitude }

init?<U: BinaryInteger>(exactly n: U) {
guard let x = T(exactly: n) else { return nil }
self.x = x
}
}
``````

So far so good.

Now let’s try to use that conformance:

``````extension Foo where T : FloatingPoint {
func foo() {
_ = self + self
}
}
``````

…and we’re hit by an error: “ambiguous use of operator `+`”.

Interestingly, if we move all the operators down into the extension that declares `Numeric` conformance, then it compiles fine. But with unconditionally-available operators, we get a compiler error.

Is this a known bug?

• • •

The actual place this arose was when trying to implement `Complex<T: SignedNumeric>`, which cannot conform unconditionally to `SignedNumeric` because the `magnitude` requirement doesn’t work when `T` is an integer type.

So I implemented the arithmetic operators on `Complex`, but could only provide `SignedNumeric` conformance when `T: FloatingPoint`. Unfortunately, that made all the basic operators “ambiguous”.

Simplified the case a bit more:

``````protocol A { static func +(lhs: Self, rhs: Self) }

protocol B: A {}

struct Foo<T: A> {
static func +(lhs: Foo, rhs: Foo) {}
}

extension Foo: A where T: B {}

extension Foo where T: B {

func soo() { self + self }
}
``````

Haven't come across it, but definitely a bug. It works fine if you substitute `+` with `foo`.

4 Likes

This definitely looks like a bug. If you haven't yet, please file it at bugs.swift.org.

1 Like

Filed as SR–7476, using @anthonylatsis’s minimal example.

2 Likes