Why isn't the TypeSolver able to resolve this without the implicit assignment first?

The asserts below behave differently for the following code:

func sum<T: Numeric>(_ numbers: [T]) -> T {
    numbers.reduce(0, +)
}

This assert works:

let doubles = [1.0, 2.0, 3.0]
assert(sum(doubles) == 6.0)

This assert refuses to compile:

assert(sum([1.0, 2.0, 3.0]) == 6.0) 

with an ambiguous use of operator '==' error.

The assignment to the constant doubles is implicit, so we still need the Swift typesolver to determine its type. It appears we get some different behavior when we assign the array first rather than just pass the array as a parameter.

The full code and errors are shown below.

import UIKit

func sum<T: Numeric>(_ numbers: [T]) -> T {
    numbers.reduce(0, +)
}

let doubles = [1.0, 2.0, 3.0]
assert(sum(doubles) == 6.0)  // No problem whatsoever

assert(sum([1.0, 2.0, 3.0]) == 6.0) // This doesn't compile due to ambiguous use of operator '=='

error: 241225.playground:10:29: ambiguous use of operator '=='
assert(sum([1.0, 2.0, 3.0]) == 6.0)
                            ^

Foundation.RunLoop:30:32: note: found this candidate in module 'Foundation'
            public static func == (a: RunLoop.SchedulerTimeType.Stride, b: RunLoop.SchedulerTimeType.Stride) -> Bool
                               ^

Foundation.Decimal:3:24: note: found this candidate in module 'Foundation'
    public static func == (lhs: Decimal, rhs: Decimal) -> Bool
                       ^

Foundation.OperationQueue:30:32: note: found this candidate in module 'Foundation'
            public static func == (a: OperationQueue.SchedulerTimeType.Stride, b: OperationQueue.SchedulerTimeType.Stride) -> Bool
                               ^

Dispatch.DispatchQueue:35:32: note: found this candidate in module 'Dispatch'
            public static func == (a: DispatchQueue.SchedulerTimeType.Stride, b: DispatchQueue.SchedulerTimeType.Stride) -> Bool
                               ^
2 Likes

When you assign the array literal to doubles without additional type context, Swift determines that it is an array with elements of the default float literal type, Double.

When you don't assign the array literal, then Swift has to look for all possible types that conform to ExpressibleByFloatLiteral and Equatable to determine the element type.

Unfortunately for your use case, you've imported UIKit, which re-exports Foundation and Dispatch. Both of these libraries have implemented types that fulfill these criteria, which causes the expression to be ambiguous. There isn't any such problem if you write the exact same code in a file that omits import UIKit.

2 Likes

This is not to say that I think this behavior is in any way reasonable; I've filed an issue that will link back to this thread.

5 Likes