1

Below is a SSCCE of a Swift 4 framework I'm working on in Xcode 9 Beta 5:

// MARK: - Protocols

public protocol BaseFoo {
    associatedtype FooBar: Bar
}



public protocol Bar {
    associatedtype BarData: DataHolder
}
public extension Bar {
    public typealias Callback = BarCallback<BarData>
}



public typealias BarCallback<Result: DataHolder> = (Result?, Error?) -> Void



public protocol DataHolder {
}



// MARK: - Implementations

public class MyFoo: BaseFoo { // Does not compile
    public typealias FooBar = MyBar
}



public protocol MyBar: Bar where BarData: MyDataHolder {
}
public protocol MyDataHolder: DataHolder {
}

But the compiler complains that "Type 'MyFoo' does not conform to protocol 'BaseFoo'". Xcode asks "Do you want to add protocol stubs?" and when I click "Fix", it does this:

public class MyFoo: BaseFoo {
    public typealias FooBar = <#type#>

    public typealias FooBar = MyBar
}

That seems to indicate that MyBar is not the proper type to satisfy FooBar, but it's clearly a DataHolder, just as required. What's going on here, and how do I fix it?

Ky -
  • 30,724
  • 51
  • 192
  • 308
  • Possible duplicate of [Unable to use protocol as associatedtype in another protocol in Swift](https://stackoverflow.com/questions/37360114/unable-to-use-protocol-as-associatedtype-in-another-protocol-in-swift) – Hamish Aug 17 '17 at 15:24
  • It is indeed as you suspect; `MyBar` is not a type that conforms to `Bar`. – Hamish Aug 17 '17 at 15:24
  • @Hamish close, but compiling with Swift 3 revealed there was one crucially missing piece of information. – Ky - Aug 17 '17 at 15:35
  • @Hamish why do you think `MyBar` is not a `Bar`? Its declaration clearly inherits. – Ky - Aug 17 '17 at 15:36
  • Ah, I missed the fact that `Bar` had an associated type, my bad. `MyBar` is not a type that conforms to `Bar` because [protocols don't conform to themselves](https://stackoverflow.com/a/43408193/2976878). – Hamish Aug 17 '17 at 15:37
  • @Hamish Now I'm even more confused. Why do you think `MyBar` conforms to `MyBar`? – Ky - Aug 17 '17 at 15:40
  • I don't – `MyBar` *doesn't* conform to `MyBar`, because it's a protocol and protocols don't conform to themselves :) – Hamish Aug 17 '17 at 15:41
  • @Hamish I see. I'd love if you elaborated more on this in an answer, because even though I found a solution to my problem, I'm not sure I know the root cause. – Ky - Aug 17 '17 at 15:43
  • I (think at least) I've already given a detailed answer to this both [here](https://stackoverflow.com/a/37360490/2976878) & [here](https://stackoverflow.com/a/43408193/2976878). Is there anything in specific you need clarifying? – Hamish Aug 17 '17 at 15:44

1 Answers1

0

Some light was shed on this when I tried to compile using Swift 3, which only required minimal changes. Now, I get two errors:

public class MyFoo: BaseFoo { // Type 'MyFoo' does not conform to protocol 'BaseFoo'
    public typealias FooBar = MyBar // Protocol 'MyBar' can only be used as a generic constraint because it has Self or associated type requirements
}

Aha! Now this is an error I'm used to dealing with. So, I put it in the class declaration as a generic parameter:

public class MyFoo<_MyBar: MyBar>: BaseFoo {
    public typealias FooBar = _MyBar
}

And now it compiles just fine! Bringing that fix back into Swift 4 gives the same result; now it compiles just fine.

So the problem was that MyBar was too generic to be used directly as a type, and needs to be abstracted through a generic parameter.

Ky -
  • 30,724
  • 51
  • 192
  • 308