Navigation Menu

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-10907] Default implementation not picked up when conforming to two protocols at once #53297

Open
swift-ci opened this issue Jun 10, 2019 · 2 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

Previous ID SR-10907
Radar None
Original Reporter TadeasKriz (JIRA User)
Type Bug
Environment

Xcode 10.2.1

Swift 5.0.1

macOS 10.14.5

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

md5: b02c78ec857e720ea4ad9f1e15a47204

relates to:

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

Issue Description:

1. Let's declare three protocols Human, HasParent and CanCook:

protocol Human {
    func breathe()
}

protocol HasParent {
    associatedtype Parent

    var parent: Parent { get }
}

protocol CanCook {
    func cook()
}

2. Let's say we want to add a default implementation of the method cook() to every Human who also has a parent (conforming to HasParent protocol), but only if the parent can cook (Parent conforming to CanCook protocol).

extension Human where Self: CanCook & HasParent, Self.Parent: CanCook {
    func cook() {
        parent.cook()
    }
}

3. Lastly, let's have two classes that implement these protocols, one of them who implements the method cook() and another that has a parent, that we want to delegate the call to:

class Father: Human, CanCook {
    func breathe() { }

    func cook() { }
}


class Toddler: Human, HasParent, CanCook {
    let parent: Human & CanCook

    init(parent: Human & CanCook) {
        self.parent = parent
    }

    func breathe() { }
} 

Expected result would be that when calling cook() on the Toddler class, the parent.cook() would get called.

Actual result is compile error:

 error: SwiftBug.playground:27:7: error: type 'Toddler' does not conform to protocol 'CanCook'
class Toddler: Human, HasParent, CanCook {
      ^

SwiftBug.playground:16:10: note: candidate has non-matching type '<Self> () -> ()'
    func cook() {
         ^

SwiftBug.playground:12:10: note: protocol requires function 'cook()' with type '() -> ()'; do you want to add a stub?
    func cook()
         ^

Note that if we change the type of parent in Toddler to Father, it works as expected. As well as changing the type of parent in Toddler to CanCook and changing the extension definition so that the conformance states Self.Parent == CanCook instead of Self.Parent: CanCook.

@swift-ci
Copy link
Collaborator Author

Comment by Tadeas Kriz (JIRA)

I suspect this behavior is caused/in line with https://bugs.swift.org/browse/SR-55

@belkadan
Copy link
Contributor

Yeah, pretty much. Human & CanCook isn't itself a type that conforms to CanCook; whatever it holds is. cc @slavapestov

@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

2 participants