While I modified my app today, I observed it suddenly took very long time to compile (it was so long that I thought Xcode hung, but the compilation succeeded eventually). I checked compilation log, but couldn't find any clue. After a lot of experiments I find I could reproduce the issue with the following code:
func sort4<Value,
Property1: Comparable,
Property2: Comparable,
Property3: Comparable,
Property4: Comparable>(
_ a: Value,
_ b: Value,
prop1: KeyPath<Value, Property1>,
comparator1: (Property1, Property1) -> Bool,
prop2: KeyPath<Value, Property2>,
comparator2: (Property2, Property2) -> Bool,
prop3: KeyPath<Value, Property3>,
comparator3: (Property3, Property3) -> Bool,
prop4: KeyPath<Value, Property4>,
comparator4: (Property4, Property4) -> Bool
) -> Bool {
let aProp1 = a[keyPath: prop1]
let bProp1 = b[keyPath: prop1]
if aProp1 != bProp1 {
return comparator1(aProp1, bProp1)
}
let aProp2 = a[keyPath: prop2]
let bProp2 = b[keyPath: prop2]
if aProp2 != bProp2 {
return comparator2(aProp2, bProp2)
}
let aProp3 = a[keyPath: prop3]
let bProp3 = b[keyPath: prop3]
if aProp3 != bProp3 {
return comparator3(aProp3, bProp3)
}
let aProp4 = a[keyPath: prop4]
let bProp4 = b[keyPath: prop4]
return comparator4(aProp4, bProp4)
}
struct Foo {
static func sort(_ lhs: Self, _ rhs: Self) -> Bool {
sort4(lhs, rhs,
prop1: \.a, comparator1: <,
prop2: \.b, comparator2: <,
prop3: \.c, comparator1: <,
prop4: \.d, comparator1: <,)
}
var a: Int
var b: Int
var c: Int
var d: Int
init(_ value: Int) {
(a, b, c, d) = (value, value, value, value)
}
}
let foos = [Foo(2), Foo(1)]
let sorted = foos.sorted(by: Foo.sort)
print(sorted)
On the other hand, however, if I reduce the property number to 2, it works fine. See code below.
func sort2<Value,
Property1: Comparable,
Property2: Comparable>(
_ a: Value,
_ b: Value,
prop1: KeyPath<Value, Property1>,
comparator1: (Property1, Property1) -> Bool,
prop2: KeyPath<Value, Property2>,
comparator2: (Property2, Property2) -> Bool
) -> Bool {
let aProp1 = a[keyPath: prop1]
let bProp1 = b[keyPath: prop1]
if aProp1 != bProp1 {
return comparator1(aProp1, bProp1)
}
let aProp2 = a[keyPath: prop2]
let bProp2 = b[keyPath: prop2]
return comparator2(aProp2, bProp2)
}
struct Foo {
static func sort(_ lhs: Self, _ rhs: Self) -> Bool {
sort2(lhs, rhs,
prop1: \.a, comparator1: <,
prop2: \.b, comparator2: <)
}
var a: Int
var b: Int
init(_ value: Int) {
(a, b) = (value, value)
}
}
let foos = [Foo(2), Foo(1)]
let sorted = foos.sorted(by: Foo.sort)
print(sorted)
I wonder why such a difference? Is it a bug? I'm using XCode 14.1, which has Swift 5.7.1.