Automatically inferring associatedtype when conforming to a refinement

I'm seeing some weird associatedtype inference behavior when conforming to a refinement of a protocol that has an associatedtype:

protocol P1 {
  associatedtype Input
  func req(_ input: Input)
}

protocol P2: P1 {
  func req2(_ input: Input)
}

extension P2 {
  func req(_ input: Input) { req2(input) }
}

struct S: P2 {
  func req2(_ input: String) { print(input) }
}

Gives error:

badassoc2.swift:14:8: error: type 'S' does not conform to protocol 'P2'
struct S: P2 {
       ^
badassoc2.swift:15:8: note: candidate has non-matching type '(String) -> ()'
  func req2(_ input: String) { print(input) }
       ^
badassoc2.swift:14:8: error: type 'S' does not conform to protocol 'P1'
struct S: P2 {
       ^
badassoc2.swift:7:8: note: protocol requires function 'req2' with type '(S.Input) -> ()'; do you want to add a stub?
  func req2(_ input: Input)
       ^
badassoc2.swift:2:18: note: protocol requires nested type 'Input'; do you want to add it?
  associatedtype Input
                 ^

It seems like the compiler should be able to figure out the type of Input without any extra help from me. Is this a compiler bug? Or something that I should not expect the compiler to be able to do for me?

I have discovered that I can fix it by adding the line associatedtype Input to protocol P2.

1 Like

I believe this is a known shortcoming, and it affects the standard library as well. The solution employed there is the same one you found, namely adding the associatedtype to the refining protocol.

For example, here’s the first few lines of BidirectionalCollection:

public protocol BidirectionalCollection: Collection
where SubSequence: BidirectionalCollection, Indices: BidirectionalCollection {
  // FIXME: Only needed for associated type inference.
  override associatedtype Element
  override associatedtype Index
  override associatedtype SubSequence
  override associatedtype Indices
  ⋮
}
3 Likes

Putting on my Swift Evolution hat…

Is there any scenario in which we don’t want this behavior? As in, could we just tell the compiler to, essentially, automatically insert override associatedtype XYZ for every associated type of the parent protocol? Are there any drawbacks to doing so?

Associated type inference is intentionally limited to a single level for performance reasons. The associated type inference engine was notorious for how unstable and bogus it could be. Not because of quality of implementation – improving the performance of type inference is itself a very complex problem fundamentally.

[ Not in citation given ]