Tuple '(key: Choice, value: Int)' and '(Choice, Int)' not equivalent?

I thought tuples are equivalent if types are the same regardless of label names?

enum Choice: CaseIterable {
    case a, b, c, d, e, f
}

let bitMap = Dictionary<Choice, Int>(uniqueKeysWithValues: Choice.allCases.enumerated().map {
    (key: $1, value: 1 << $0)   // error: Initializer 'init(uniqueKeysWithValues:)' requires the types '(key: Choice, value: Int)' and '(Choice, Int)' be equivalent
//    ($1, 1 << $0)     // this works
})

Xcode Version 13.0 beta 5 (13A5212g)

From the docs:

When an element of a tuple type has a name, that name is part of the type.

But it seems unlabeled tuple can become labeled with no type mismatch?

func foo() -> (a: Int, b: Int) {
// these all work:
    (1, 2)
//    (a: 1, 2)
//    (1, b: 2)
}

print(foo())    // (a: 1, b: 2)

is no label is same as any label?

Because the compiler infers the labels due to the return type of the function.

Just like in the examples from the docs:

var someTuple = (top: 10, bottom: 12)  // someTuple is of type (top: Int, bottom: Int)
someTuple = (top: 4, bottom: 42) // OK: names match
someTuple = (9, 99)              // OK: names are inferred
1 Like

This is why I'm confused, no type mismatch compile error when the second element is not bit shift for the same mismatched labeled tuple:

enum Choice: CaseIterable {
    case a, b, c, d, e, f
}

let bitMap = Dictionary<Choice, Int>(uniqueKeysWithValues: Choice.allCases.enumerated().map {
//    (key: $1, value: 1 << $0)   // error: Initializer 'init(uniqueKeysWithValues:)' requires the types '(key: Choice, value: Int)' and '(Choice, Int)' be equivalent
//    (key: $1, value: $0)    // 👈 !!! exact same tuple as above, now no problem!
    (truck: $1, you: $0)      // no matter what the labels are, all no problem!
//    ($1, 1 << $0)     // this works
})

Seems like the bit shift one produce compile error, others fine

func generic<T>(_ closure: () -> (T, T)) -> (wtf: T, hey: T) {
    closure()
}

print(generic { (truck: 1, you: 2) })   // (wtf: 1, hey: 2)

From the above example, it seems labeled tuple can become unlabeled, and from unlabeled tuple to labeled:

labeled-tuple -> unlabeled-tuple -> labeled-tuple

this appears to be a valid way to re-label a tuple.

So I don't see why my original case should not compile. It's clearly not caring what the tuple element labels are if it ends in an unlabeled-tuple.

Interestingly, this gives no errors:

let bitMap = Dictionary<Choice, Int>(uniqueKeysWithValues: Choice.allCases.enumerated().map {
    let i = 1 << $0
    return (key: $1, value: i)
})

And this works too:

let bitMap = Dictionary<Choice, Int>(uniqueKeysWithValues: Choice.allCases.enumerated().map {
    let t = (key: $1, value: 1 << $0)
    return t
})

I don't really understand why.

https://bugs.swift.org/browse/SR-15069

Terms of Service

Privacy Policy

Cookie Policy