Uploaded image for project: 'Swift'
  1. Swift
  2. SR-522

Protocol funcs cannot have covariant returns

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Open
    • Priority: Medium
    • Resolution: Unresolved
    • Component/s: Compiler
    • Labels:
      None
    • Environment:

      Xcode 7.2

      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.

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                samballantyne Sam Ballantyne
                Reporter:
                hlovatt Howard Lovatt
              • Votes:
                12 Vote for this issue
                Watchers:
                22 Start watching this issue

                Dates

                • Created:
                  Updated: