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-1297] Method parameters list interpreted as a single tuple (tuple "unsplat"), making behavior disturbing #43905

Closed
AliSoftware opened this issue Apr 22, 2016 · 2 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself type checker Area → compiler: Semantic analysis

Comments

@AliSoftware
Copy link
Contributor

Previous ID SR-1297
Radar None
Original Reporter @AliSoftware
Type Bug
Status Closed
Resolution Done
Environment

Swift 2.2 & Swift 3.0

Tested in Swift REPL 2.2

Apple Swift version 2.2 (swiftlang-703.0.18.1 clang-703.0.29)
Target: x86_64-apple-macosx10.9

Tested in IBM Swift Sandbox 3.0

https://swiftlang.ng.bluemix.net/
"Ver. 3.0 (Mar 24, 2016)"

Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug, TypeChecker
Assignee None
Priority Medium

md5: c93d61c824e21df530ad3b1e7dc31e2c

is duplicated by:

  • SR-1511 String contentsOfURL initializer compiles when it should not

relates to:

  • SR-1261 Swift incorrectly identifies passing a tuple to a function as a tuple splat
  • SR-1338 Inconsistent "Ambiguous use of 'xxx'" error when calling an Obj-C method with 2 versions that take a block with 1 or 2 parameters respectively.

Issue Description:

Description

When there exists a method that takes an unnamed, unconstrained generic argument, like foo<T>(x: T), calling that method with any number of named or unnamed arguments is interpreted as being a single tuple argument, which makes it very confusing.

Typical example: String(format:…)

The typical example that made me first encounter this behavior is using String(format: ) without importing Foundation.

// DON'T import Foundation
String(format: "%d:%02d:%02d", 5, 2, 3) // returns «("%d:%02d:%02d", 5, 2, 3)»

After some investigation I realized it's because String(format: ) is not defined without importing Foundation but instead of having a compiler error, it interprets that call as:

String( (format: "%d:%02d:%02d", 5, 2, 3) )

Thus interpreting the expression as a single tuple argument and converting it to its string representation.

This is because the compiler matches the call with the definition of String.init<T>(_ v: T), which is possible only because the compiler allows itself to interpret the arguments as a tuple being "unsplatted" — and making T match that tuple type.

This means that any similar call with arbitrary arguments, like String(foo: 5, bar: true, baz: "whoops") also compiles, instead of being reported as a compilation error.

How to Reproduce

// Declare a method that accept a generic, unnamed argument
func foo<T>(x: T) {
  print(x)
}
// Call it with any arbitrary arguments
foo(x: 1, y: 2)     // prints (1, 2)
foo(bar: true, baz: "what?") // prints (true, "what?")

// observe that the lines above actually acts like if the calls were:
foo((x: 1, y: 2))   // prints (1, 2)
foo((bar: true, baz: "what?")) // prints (true, "what?")

Actual Result

The parameter list is interpreted as a single argument of type tuple, like a "tuple unsplat" operation, making the behavior disturbing, and the compiler magic masking what should be reported as a compilation error.

Expected Result

The compiler should not auto-wrap the parameters in a tuple implicitly, and instead generate a compilation error stating that there is no method String.init(format: ) defined (or suggesting to use an explicit tuple).

Note: don't confuse w/ Swift 3 removal of tuple splatting

I know that tuple splatting will be removed in Swift 3.0, but this behavior is kinda the opposite of tuple splatting, as it implicitly wraps a parameters list into a tuple, instead of unwrapping a tuple into a parameter list.

Tuple splatting (passing a tuple of 2 values a a single argument to a function expecting 2 arguments) already do produce a proper depreciation warning in Swift 3.0. But the code described above in this issue (which is the opposite, passing 2 arguments to a method expecting one tuple) does NOT produce any warning.

That's why I'm not sure the removal of tuple splatting in Swift 3.0 will fix this behavior too — being somehow a different (even the opposite) mechanism — and if this opposite behavior (tuple "unsplatting") was also considered for removal too already or not.

@AliSoftware
Copy link
Contributor Author

This seems to have been fixed in latest Swift 3.0 snapshots? (only tested in the IBM Sandbox but now I've got a proper error there)

@palimondo
Copy link
Mannequin

palimondo mannequin commented May 10, 2017

I think this issue can be closed. Using the provided example String(format: "%d:%02d:%02d", 5, 2, 3)

Swift version 3.1 reports error:

error: repl.swift:1:1: error: 'init' has been renamed to 'init(describing:)'

Swift version 4.0-dev (LLVM 3df4892fbe, Clang 1a30829a18, Swift f6f3ed0)

error: incorrect argument label in call (have 'format:_:_:_:', expected 'stringInterpolation:_:_:_:')
String(format: "%d:%02d:%02d", 5, 2, 3)
      ^~~~~~~
       stringInterpolation
(swift) error: repl.swift:1:1: error: 'init' has been renamed to 'init(describing:)'

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
This issue was closed.
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 type checker Area → compiler: Semantic analysis
Projects
None yet
Development

No branches or pull requests

1 participant