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-7332] Conditional conformance over array of heterogenous values that share a protocol conformance fails #49880

Closed
swift-ci opened this issue Apr 2, 2018 · 4 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself

Comments

@swift-ci
Copy link
Collaborator

swift-ci commented Apr 2, 2018

Previous ID SR-7332
Radar None
Original Reporter guidomb (JIRA User)
Type Bug
Status Resolved
Resolution Won't Do
Environment

macOS 10.13.3 (17D102)

Xcode Version 9.3 (9E145)

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

md5: 2d22a25cc9169583760be101f06e3eaf

relates to:

  • SR-55 non-@objc protocol existentials do not conform to their own protocol type

Issue Description:

The following code that makes an Array to conform to Protocol only if all its elements conform to that same protocol fails to compile when trying to assign such array to variable declared as the protocol's type. The following is an example that reproduces the error

public protocol QueryStringConvertible {
    
    var asQueryString: String { get }
    
}

extension Array: QueryStringConvertible where Element: QueryStringConvertible {
    
    public var asQueryString: String {
        return self.reduce("") { $0.isEmpty ? $1.asQueryString : "\($0)&\($1.asQueryString)"  }
    }
    
}

extension Dictionary: QueryStringConvertible where Key == String, Value: CustomStringConvertible {
    
    public var asQueryString: String {
        return self.reduce("") { ($0.isEmpty ? "" : "\($0)&") + "\($1.key)=\($1.value)" }
    }
    
}

struct Person: QueryStringConvertible {
    
    let firstName: String
    let lastName: String
    
    public var asQueryString: String {
        return "firstName=\(firstName)&lastName=\(lastName)"
    }
    
}

func bar<Q: QueryStringConvertible>(query: Q) -> String{
    return "QUERY: " + query.asQueryString
}

func baz(query: QueryStringConvertible) -> String {
    return "QUERY: " + query.asQueryString
}

let dictionary = [ "param1" : "value1", "param2" : "value2" ]
dictionary.asQueryString
let person = Person(firstName: "John", lastName: "Doe")
person.asQueryString
bar(query: dictionary)
bar(query: person)
bar(query: [dictionary])
bar(query: [person])

// THIS does not compile -> '<Q where Q : QueryStringConvertible> (query: Q) -> String' requires that 'Any' conform to 'QueryStringConvertible'
bar(query: [dictionary, person])

baz(query: dictionary)
baz(query: person)
baz(query: [dictionary])
baz(query: [person])

//  This does not compile -> Contextual type 'QueryStringConvertible' cannot be used with array literal
baz(query: [dictionary, person])
@belkadan
Copy link
Contributor

belkadan commented Apr 3, 2018

Protocol values (the type QueryStringConvertible) aren't the same as "a type that conforms to QueryStringConvertible", and the conditional conformance machinery doesn't actually look at the values in the array, just the declared element type of the Array itself. You can see SR-55 for more information, although it's not quite the same problem.

@swift-ci
Copy link
Collaborator Author

swift-ci commented Apr 3, 2018

Comment by Guido Marucci Blas (JIRA)

@belkadan I don't understand why the following snippet does not compile:

let qscArray: QueryStringConvertible = [dictionary as QueryStringConvertible, person as QueryStringConvertible

but that following code throws a warning suggesting that this will work in future versions of Swift

let qscArray = [dictionary as QueryStringConvertible, person as QueryStringConvertible] as? QueryStringConvertible
warning: Swift runtime does not yet support dynamically querying conditional conformance ('Swift.Array<__lldb_expr_1.QueryStringConvertible>': '__lldb_expr_1.QueryStringConvertible')

If this will work in a future version why this can be resolved at runtime but not at compile time. Are there any other restrictions that makes this harder or impossible to be implemented at compile time. I know nothing about compilers but it is quite not intuitive to me that if I declared a conditional conformance to a protocol to an Array I cannot bind it to variable of that protocol's type

@belkadan
Copy link
Contributor

belkadan commented Apr 3, 2018

It won't work in the future version. The message you're getting is saying that it can't even ask the question at the moment; once it is able to ask the question, it will not work.

@swift-ci
Copy link
Collaborator Author

swift-ci commented Apr 4, 2018

Comment by Guido Marucci Blas (JIRA)

@belkadan thanks for clarifying that! Can you point me to any resource that may explain the design decision behind why the compiler cannot, in this example, declare `[dictionary as QueryStringConvertible, person as QueryStringConvertible]` as type `QueryStringConvertible`. I'm curious about the design decisions or limitations.

@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