Swift - Overloading “+” Operator - “Cannot Convert Value of type” Erro

I'm hitting a compiler error that is best illustrated by the small code snippet below.
enter image description here

My goal is be able to perform addition on instances of MyEnum directly along side CGFloat. Now for simple cases this works perfectly fine however for more complex statements as seen in let three example below it causes a compiler error. I understand there are several alternate architectures I can pick from including static let or enums with a RawValue but that is not what I'm asking here. I'd really like to understand what is causing the compiler problem in isolated code snippet I've included below.

I have a feeling the issue is coming down the precedence (compiler can't decide to evaluate the first+second parts first or the second+third parts first) but I'm not sure. I've tried several variations including,

  • Moving the operator functions to global scope.
  • Moving the two operator functions that take CGFloat arguments to an extension CGFloat instead.

Here is an boiled down code snippet that illustrates the issue.

enum MyEnum {
   case someOption

   var value: CGFloat { ... }
}

extension MyEnum {
    static func + (left: MyEnum, right: MyEnum) -> CGFloat {
        return left.value + right.value
    }
    static func + (left: MyEnum, right: CGFloat) -> CGFloat {
        return left.value + right
    }
    static func + (left: CGFloat, right: MyEnum) -> CGFloat {
        return left + right.value
    }
}

let one = MyEnum.someOption + 1
let two = MyEnum.someOption + MyEnum.someOption
let three = MyEnum.someOption + MyEnum.someOption + MyEnum.someOption // fails
let four = (MyEnum.someOption + MyEnum.someOption) + MyEnum.someOption // also fails

To add more confusion if I create a completely new custom operator called for example and I mark it part of the AdditionPrecedence group everything works totally fine. Ultimately I want the + operator to make thing intuitive.

enum MyEnum {
    case someOption

    var value: CGFloat { ... }
}

infix operator •: AdditionPrecedence

extension MyEnum {
    static func • (left: MyEnum, right: MyEnum) -> CGFloat {
        return left.value + right.value
    }
    static func • (left: MyEnum, right: CGFloat) -> CGFloat {
        return left.value + right
    }
    static func • (left: CGFloat, right: MyEnum) -> CGFloat {
        return left + right.value
    }
}

let one = MyEnum.someOption • 1
let two = MyEnum.someOption • MyEnum.someOption
let three = MyEnum.someOption • MyEnum.someOption • MyEnum.someOption // works totally fine now
2 Likes

cc @hborla @xedin :face_with_monocle:

I'm almost certain this is another bug with the "favoring" hack described here:

Unfortunately this is due to the performance hack we have in the solver that merges together types of arguments for + and other "homogeneous" operators that have (Self, Self) -> Self overloads.

2 Likes