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-6989] Trailing closure syntax shouldn't apply when argument is generic but not explicitly a function #49537

Open
mdiep opened this issue Feb 13, 2018 · 6 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

@mdiep
Copy link
Contributor

mdiep commented Feb 13, 2018

Previous ID SR-6989
Radar None
Original Reporter @mdiep
Type Bug
Environment

Swift 4.0.2, 4.1

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

md5: 48568a9aa9b62907251dc6d3a4f85009

Issue Description:

As discovered here: ReactiveCocoa/ReactiveSwift#601 (comment)

This code:

public final class Object<T> {
    public func map<U>(_ transform: @escaping (T) -> U) -> Object<U> {
        return Object<U>()
    }
    
    public func map<U>(value: U) -> Object<U> {
        return Object<U>()
    }
}

let mapped = Object<Int>().map { $0 as Int? }
let expected: Object<Int?> = mapped

yields this error:

error: MyPlayground.playground:6:30: error: cannot convert value of type 'Object<(Int?) -> Int?>' to specified type 'Object<Int?>'
let expected: Object<Int?> = mapped
                             ^~~~~~

This does not seem like a valid application of trailing closure syntax. Specifically: trailing closure syntax should only apply when the argument is definitely a function (U) -> T—not when it's any generic value U to which you can pass a function.

I'm hoping you'll consider this a bug. But if not, I'd be happy to open a swift-evolution discussion. 🙂

@belkadan
Copy link
Contributor

I'm inclined to agree it's a bug, but fixing it would be source-breaking. Might be one of those warning-in-Swift-4, error-in-Swift-5 things.

@rudkx?

@xwu
Copy link
Collaborator

xwu commented Feb 14, 2018

The generic argument could be a disfavored overload instead of outright disallowed. It'd still be technically a potentially source-breaking change but in practice I'd imagine it should work pretty much as users intend.

@swift-ci
Copy link
Collaborator

Comment by Anders Ha (JIRA)

Even if we provide a more specific variant that accepts `@escaping (Value) -> U?`, the compiler still picks the most generic variant that accepts just `U`.

@belkadan
Copy link
Contributor

The original version should already count as "more specific". That's somewhat separable from the trailing-closure-for-non-closure-parameter thing, though.

@mdiep
Copy link
Contributor Author

mdiep commented Apr 17, 2018

The above code sample works on master as of 44531db. The first overload is chosen.

But I think trailing closure syntax should be disallowed when the argument isn't specifically a parameter. i.e., this should error:

public final class Object<T> {  
    public func map<U>(value: U) -> Object<U> {
        return Object<U>()
    }
}

_ = Object<Int>().map { $0 as Int? }

@belkadan
Copy link
Contributor

@jckarter, do you think such a change would have to go through swift-evolution? What about if it were just a warning?

@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 type checker Area → compiler: Semantic analysis
Projects
None yet
Development

No branches or pull requests

4 participants