Does conditional conformance works with concrete same type requirements?

I'm trying to make CountableClosedRange conforms with some protocols using conditional conformance and I am receiving an unexpected error.
The following code illustrates the problem:

import Foundation

protocol P {
    func doSomething()
}

struct Generic<T> {
    let value: T
}

extension Int: P {
    func doSomething() {
        print("bla")
    }
}

extension Generic: P where T == Int {
    
    func doSomething() {
        print("do something generic")
    }
}

extension CountableClosedRange: P where Bound == Int {
    func doSomething() {
        print("do something \(upperBound)")
    }
}

let pArray: [P] = [10, Generic<Int>(value: 5), 10...20]

The compiler is generating an error stating that CountableClosedRange does not conforms to expected element type P, but I think it should work as it works when I only set generic type and In in the array.
What am I missing?

I think the error message is just deceiving. In reality it looks like the type inference of the array literal is too complicated for the compiler.

In any case, simply refactoring the last line into two steps works (in Swift 4.1.2/Xcode 9.4.1):

let intRange: CountableClosedRange<Int> = 10 ... 20
let pArray: [P] = [10, Generic<Int>(value: 5), intRange as P]
2 Likes

It depends which version of Swift you're using.

Welcome to Apple Swift version 4.1.2 (swiftlang-902.0.54 clang-902.0.39.2)

error: repl.swift:30:50: error: value of type 'CountableClosedRange<Int>' does not conform to expected element type 'P'
let pArray: [P] = [10, Generic<Int>(value: 5), 10...20]
                                               ~~^~~~~
                                                       as P

Your example works in Swift 4.2 (Xcode 10 beta 6).

Welcome to Apple Swift version 4.2 (swiftlang-1000.0.36 clang-1000.0.4)

pArray: [P] = 3 values {
  [0] = 10
  [1] = {
    value = 5
  }
  [2] = 10...20
}

If you change the conditional conformance to
extension CountableClosedRange: P where Bound: P {
it will also work in Swift 4.1.2 (Xcode 9.4.1)

Can you share why it's working in Swift 4.2 but not in the current version? Was there some kind of a bug that prevented it? At first glance I thought it was related to SE-0213, but the status says it's implemented for Swift 5 rather then Swift 4.2.

1 Like

Thanks for your suggestion.
I could make it work only creating an extra variable for range and didn't have to type cast it to P when adding it to array.

1 Like

@DevAndArtist, it doesn't work in Swift 4.1, but I don't know why.

Swift 4.2 has conditional conformance bug fixes,
e.g. https://bugs.swift.org/browse/SR-7192

1 Like