Can code-block local types conform to protocols?

class SortInPlaceTests: XCTestCase {

    //...

    func testSortStability() {
        struct Sample: Comparable {  // ERROR: Type 'Sample' does not conform to protocol 'Comparable'
            static func == (lhs: Sample, rhs: Sample) -> Bool {
                return lhs.first == rhs.first
            }
            static func < (lhs: Sample, rhs: Sample) -> Bool {
                return lhs.first < rhs.first
            }

            let first: Int
            let second: Int
        }
        //...
    }

}

The error had a Fix-it to add stubs, and it would add the one for < that I already had. I remember C++ having wonky limitations on what code-local functions and types could do; do we have similar limitations (on types)?

1 Like

In Xcode 10.3 (Swift 5.0.1), I observe that a type within a function can conform to Equatable:

// This works:
func foo() {
  struct Bar: Equatable {
    static func == (lhs: Bar, rhs: Bar) -> Bool { return true }
  }
}

But not Comparable:

// This gives an error that Bar does not conform to Comparable:
func foo() {
  struct Bar: Comparable {
    static func == (lhs: Bar, rhs: Bar) -> Bool { return true }
    static func < (lhs: Bar, rhs: Bar) -> Bool { return true }
  }
}

Outside of a function, the latter type works properly:

//This works:
struct Bar: Comparable {
  static func == (lhs: Bar, rhs: Bar) -> Bool {  return true }
  static func < (lhs: Bar, rhs: Bar) -> Bool { return true }
}

I don’t know what causes this bug, but it is definitely a bug.

Filed at SR-11482 ("Some protocols cannot be conformed by code-block-local types").

I think this only appears to work because of automatic Equatable synthesis. If you attempt to use the conformance, it looks like a synthesized implementation is called, not the one provided.

2 Likes