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-522] Protocol funcs cannot have covariant returns #43139

Open
swift-ci opened this issue Jan 12, 2016 · 7 comments
Open

[SR-522] Protocol funcs cannot have covariant returns #43139

swift-ci opened this issue Jan 12, 2016 · 7 comments
Assignees
Labels
compiler The Swift compiler in itself conformances Feature → protocol: protocol conformances feature A feature request or implementation improvement protocol Feature → type declarations: Protocol declarations type checker Area → compiler: Semantic analysis

Comments

@swift-ci
Copy link
Collaborator

swift-ci commented Jan 12, 2016

Previous ID SR-522
Radar rdar://problem/17906373
Original Reporter hlovatt (JIRA User)
Type Bug

Attachment: Download

Environment

Xcode 7.2

Additional Detail from JIRA
Votes 17
Component/s Compiler
Labels Bug
Assignee samballantyne (JIRA)
Priority Medium

md5: 25aabb7ea4b4c8e107945dc27bb41814

is duplicated by:

  • SR-629 Protocol composition types should be covariant with composing protocols for protocol conformance
  • SR-731 Covariant overrides don't work with protocols
  • SR-733 Contravariant overrides on return type don't work with protocols
  • SR-1950 Read-only protocol property requirements not satisfied by subtypes, when they should be
  • SR-2306 Should a noescape closure be a subtype of an escaping closure?
  • SR-4103 Allow protocol conformance by promoting property getter of type T to T?
  • SR-4161 Subtyping of Optionals incomplete
  • SR-4694 Subtyping Properties and Return Types for Protocol Conformance
  • SR-5266 Swift protocol doesn't compile when using a subclass in the property implementation
  • SR-6187 Swift does not infer the signature automatically
  • SR-6220 Optional promotion when conforming to protocol
  • SR-7312 Conforming to protocol using constrained generic

relates to:

  • SR-5858 Incorrectly implementing LocalizedError protocols does not result in an error at compile time but an incorrect error localized description

Issue Description:

Currently Swift is inconsistent on how it handles covariant return types, consider the code below:

class Top {}
class Bottom: Top {}

protocol P {
    func mT() -> Top
    typealias A: Top
    func mA() -> A
}

struct S: P {
    func mT() -> Top { // Must be `Top` otherwise *type's declaration* gets error "does not conform to protocol P"
        return Bottom()
    }
    typealias A = Top
    func mA() -> Top { // Must be `Top` otherwise *type's declaration* gets error "does not conform to protocol P"
        return Bottom()
    }
}

class BC<G: Top>: P {
    func mG() -> G {
        fatalError("Needs to be overridden")
    }
    func mT() -> Top {  // Must be `Top` otherwise *type's declaration* gets error "does not conform to protocol P"
        fatalError("Needs to be overridden")
    }
    typealias A = Top
    func mA() -> Top { // Must be `Top` otherwise *type's declaration* gets error "does not conform to protocol P"
        fatalError("Needs to be overridden")
    }
}

class DC: BC<Top> {
    override func mG() -> Bottom { // Can be Bottom!
        return Bottom()
    }
    override func mT() -> Bottom { // Can be ottom!
        return Bottom()
    }
    override func mA() -> Bottom { // Can be Bottom!
        return Bottom()
    }
}

The behaviour is odd in that if a class overrides a method from another class then covariant return types are allowed. However if a class or struct implements a method from a protocol then it can't implement with a covariant return type.

When you implement a method with a protocol extension you get similar behaviour in that a class that overrides the already implemented behaviour can now have a covariant return type:

protocol PE {
    func mT() -> Top
}

extension PE {
    func mT() -> Top { // Must be `Top` otherwise **compiler crashes** (seg. fault: 11)
        fatalError("Needs to be overridden")
    }
}

class CE: PE {
    func mT() -> Bottom { // Can be Bottom!
        return Bottom()
    }
}

Chris Lattner on swift-evolution suggested that this is a bug and in all cases covariant return types should be allowed.

Above code in attached project.

@belkadan
Copy link
Contributor

This no longer crashes on master, but it's still rejected.

@swift-ci
Copy link
Collaborator Author

Comment by Howard Lovatt (JIRA)

Even not crashing is a help, so that is definitely progress. Currently this bug is hard to track down in your code because you don't know where the compiler crashed!

@slavapestov
Copy link
Member

slavapestov commented Mar 1, 2017

More generally, we want protocol witnesses and method overrides in every case where a function conversion is allowed, so for example this should work:

protocol P {
  func foo(x: String)
}

struct S : P {
  func foo(x: String?) { }
}

@swift-ci
Copy link
Collaborator Author

swift-ci commented Feb 5, 2018

Comment by Sam Ballantyne (JIRA)

Is there any progress on this?

@belkadan
Copy link
Contributor

belkadan commented Feb 5, 2018

This does not affect ABI. Please don't add that label if you're not working on ABI support.

@swift-ci
Copy link
Collaborator Author

Comment by Guillaume Le Souchu (JIRA)

Hi there, any progress have been made on this issue?

@swift-ci
Copy link
Collaborator Author

Comment by Maarten Billemont (JIRA)

Note that the extension suggestion from the description is not viable. Confusingly the instance gains both a mT() -> Top as well as a mT() -> Bottom and its type determines which function resolves. This can be quite surprising and perhaps could be considered a bug of its own?

class Top {}
class Bottom: Top {}
protocol PE {
    func mT() -> Top
}
extension PE {
    func mT() -> Top {
        fatalError("Needs to be overridden")
    }
}
class CE: PE {
    func mT() -> Bottom { // Can be Bottom!
        return Bottom()
    }
}

let ce = CE()
let pe: PE = ce

print( ce.mT() )
print( pe.mT() ) // Fatal error: Needs to be overridden

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
@AnthonyLatsis AnthonyLatsis added feature A feature request or implementation conformances Feature → protocol: protocol conformances protocol Feature → type declarations: Protocol declarations and removed bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. labels Jan 27, 2023
@AnthonyLatsis AnthonyLatsis self-assigned this Jan 27, 2023
@AnthonyLatsis AnthonyLatsis added type checker Area → compiler: Semantic analysis duplicate Resolution: Duplicates another issue improvement and removed duplicate Resolution: Duplicates another issue labels Jan 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler The Swift compiler in itself conformances Feature → protocol: protocol conformances feature A feature request or implementation improvement protocol Feature → type declarations: Protocol declarations type checker Area → compiler: Semantic analysis
Projects
None yet
Development

No branches or pull requests

4 participants