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-12754] generic overload distinguished by number of parameters of passed function #55199

Closed
mattneub opened this issue May 8, 2020 · 4 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself

Comments

@mattneub
Copy link

mattneub commented May 8, 2020

Previous ID SR-12754
Radar None
Original Reporter @mattneub
Type Bug
Status Closed
Resolution Duplicate
Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug
Assignee None
Priority Medium

md5: b58ab3c757b250eadaa7853953acb03c

duplicates:

  • SR-8563 Ambiguous type deduction for input argument for closure using generic func

Issue Description:

This compiles and works as expected:

struct TestFinder {
    func doSomething<T,U>(_ function: (T,U) -> Void) -> Void {
        print("two")
    }
    func doSomething<T,U,V>(_ function: (T,U,V) -> Void) -> Void {
        print("three")
    }
    func doSomething<T,U,V,W>(_ function: (T,U,V,W) -> Void) -> Void {
        print("four")
    }
}
func f(_ s1: String, _ s2: String, _ s3: String, _ s4: String) -> Void {}
TestFinder().doSomething(f) // "four"

But if you add a version with one passed function parameter, everything breaks down:

struct TestFinder {
    func doSomething<T>(_ function: (T) -> Void) -> Void {
        print("one") // compile error: this is seen as a candidate...
    }
    func doSomething<T,U>(_ function: (T,U) -> Void) -> Void {
        print("two")
    }
    func doSomething<T,U,V>(_ function: (T,U,V) -> Void) -> Void {
        print("three")
    }
    func doSomething<T,U,V,W>(_ function: (T,U,V,W) -> Void) -> Void {
        print("four") // ...and so is this
    }
}

Now we can't compile, because the first version is seen as a candidate. And indeed, if we remove the other versions, we still compile!

struct TestFinder {
    func doSomething<T>(_ function: (T) -> Void) -> Void {
        print("one")
    }
}
func f(_ s1: String, _ s2: String, _ s3: String, _ s4: String) -> Void {}
TestFinder().doSomething(f) // compiles!

Evidently, this function with four parameters is seen by the compiler as "fitting" the declaration with just one generic parameter.

I'm not going to try to conjecture why that is. Okay, I'll conjecture: it might have something to do with the legacy of parameter lists as tuples. But I still see it as a bug, because even though this compiles and runs as it stands, I cannot find a way, inside `doSomething`, to call the function `function` that was passed in. It is typed as taking one parameter, and I can't find a parameter type that will satisfy the compiler:

struct TestFinder {
    func doSomething<T>(_ function: (T) -> Void) -> Void {
        function( /* ??? what goes here? */ )
    }
}
func f(_ s1: String, _ s2: String, _ s3: String, _ s4: String) -> Void {}
TestFinder().doSomething(f) // compiles!

So I regard it as a bug that the one-generic version of `doSomething` is seen by the compiler as satisfied by passing the four-parameter function `f`.

@LucianoPAlmeida
Copy link
Collaborator

@mattneub This is fixed on master, can you please verify in the latest snapshot and close? Thank's 🙂
I think is a dupe of SR-8563

@mattneub
Copy link
Author

mattneub commented May 8, 2020

Thanks so much @LucianoPAlmeida!

Okay, so I tested with the May 4 2020 Swift 5.3 Development toolchain, and sure enough, we now compile with all four variants of the `doSomething` method present.

If we remove all but the first (one parameter) version of `doSomething`, we still compile and that method is called. If we express the four `function` parameters as a single tuple and force cast with `as! T`, the `function` is called correctly.

So if that is acceptable behavior, the bug is fixed. I find that last bit a little surprising, but it's nothing one can't live with; the key point is that, faced with a choice of all four, the compiler picks the four-parameter version of `doSomething`, which is the expected behavior in the larger sense.

@LucianoPAlmeida
Copy link
Collaborator

I think this is expected behavior, thanks for verifying 🙂
Resolving as dupe
cc @xedin

@mattneub
Copy link
Author

mattneub commented May 8, 2020

@LucianoPAlmeida Cool, thanks again.

@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
Projects
None yet
Development

No branches or pull requests

2 participants