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

Swift uses wrong default implementation for function defined in constrained and unconstrained protocol extensions

    Details

    • Type: Bug
    • Status: Resolved
    • Priority: Medium
    • Resolution: Invalid
    • Component/s: Compiler
    • Labels:
      None
    • Environment:

      Version 7.3 (7D175), default Swift toolchain (Swift 2.2).

      Description

      Take a protocol, with a protocol extension providing a default implementation of function A, which in turn calls function B. Function B has two default implmentations: one in an extension of the protocol which is constrained to a particular type, another in an unconstrained extension.

      When calling function B directly on an instance of the type which matches the constrained extension's constraint, the correct implementation is used. That is, the implementation in the constrained extension.

      However, when function A is called, it's call to function B always uses the implementation in the unconstrained extension.

      This seems counter to the following in the Swift book:

      If a conforming type satisfies the requirements for multiple constrained extensions that provide implementations for the same method or property, Swift will use the implementation corresponding to the most specialized constraints.

      The following code demonstrates this (can be run in a playground):

      class Bar: Foo {}
      class Qux: Foo {}
      
      protocol Foo {}
      
      extension Foo {
          func callFooFromExtension() {
              foo()
          }
      }
      
      extension Foo {
          func foo() {
              NSLog("Plain foo")
          }
      }
      
      extension Foo where Self: Qux {
          func foo() {
              NSLog("Qux foo")
          }
      }
      
      let b = Bar()
      let q = Qux()
      
      b.foo() // Logs "Plain foo"
      b.callFooFromExtension() // Logs "Plain foo"
      
      q.foo() // Logs "Qux foo"
      q.callFooFromExtension() // Logs "Plain foo", which is unexpected
      

      If foo() is declared in the protocol itself, this problem does not occur:

      protocol Foo {
          func foo()
      }
      
      q.callFooFromExtension() // Logs "Qux foo", as expected
      

        Attachments

          Activity

            People

            • Assignee:
              Unassigned
              Reporter:
              armadsen Andrew Madsen
            • Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: