Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-15539] Type inference inconsistency with tuple labels #57842

Open
lorentey opened this issue Dec 1, 2021 · 2 comments
Open

[SR-15539] Type inference inconsistency with tuple labels #57842

lorentey opened this issue Dec 1, 2021 · 2 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself

Comments

@lorentey
Copy link
Member

lorentey commented Dec 1, 2021

Previous ID SR-15539
Radar rdar://problem/85902780
Original Reporter @lorentey
Type Bug
Environment

Swift 5.5.1 in Xcode 13.1 (13A1030d)
swift-driver version: 1.26.9 Apple Swift version 5.5.1 (swiftlang-1300.0.31.4 clang-1300.0.29.6)
Target: x86_64-apple-macosx12.0

Additional Detail from JIRA
Votes 1
Component/s Compiler
Labels Bug
Assignee None
Priority Medium

md5: f873aa77f48f33dc661c3181887b2ad6

Issue Description:

In the swift-collections package, we have an OrderedDictionary type that provides a unique-keys-and-values initializer:

extension OrderedDictionary {
  public init<S: Sequence>(
    uniqueKeysWithValues keysAndValues: S
  ) where S.Element == (Key, Value) { ... }
}

I think it is reasonable to expect that we should be able to pass a standard `Dictionary` to this initializer. Alas, this doesn't work, as `Dictionary` uses the labeled tuple `(key: Key, value: Value)` as its `Element` type, and the tuple labels are evidently considered significant in this case. Simplified example:

func test<S: Sequence>(_ value: S)
where S.Element == (Int, String) {
  print(1)
}

let d = [1: "one", 2: "two", 3: "three"]

test(d)
// error: Global function 'test' requires the types 'Dictionary<Int, String>.Element' (aka '(key: Int, value: String)') and '(Int, String)' be equivalent

To work around this issue, we added an overload for the initializer that took a sequence with a labeled tuple:

func test<S: Sequence>(_ value: S)
where S.Element == (Int, String) {
  print(1)
}

func test<S: Sequence>(_ value: S)
where S.Element == (key: Int, value: String) {
  print(2)
}

let d = [1: "one", 2: "two", 3: "three"]

test(d) // OK, prints 2

This resolved this usability issue, but it turns out it introduces a bogus ambiguity in certain cases where type inference is used: (see apple/swift-collections#125

func test<S: Sequence>(_ value: S)
where S.Element == (Int, String) {
  print(1)
}

func test<S: Sequence>(_ value: S)
where S.Element == (key: Int, value: String) {
  print(2)
}

test([1, 2, 3].map { ($0, "\($0)") })
// error: ambiguous use of 'test'

test([1, 2, 3].map { (key: $0, value: "\($0)") })
// error: ambiguous use of 'test'

Removing either of the overloads allows both expressions to successfully type check. (But breaks the case where inference isn't used.)

It seems to me that there is no ambiguity here, even if we allow tuple labels to be inferred in this case – the type checker should prefer the overload that has matching labels.

@lorentey
Copy link
Member Author

lorentey commented Dec 1, 2021

@swift-ci create

@lorentey
Copy link
Member Author

lorentey commented Dec 1, 2021

(We could use the `@_disfavoredOverload` attribute on one of the initializers to work around this issue; however, that attribute isn't public, and I think ideally this ought to work without such workarounds.)

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself
Projects
None yet
Development

No branches or pull requests

1 participant