How to use constrained protocol syntax in the inheritance clause of a concrete type?

On Xcode14beta5, macOS Ventura 13.0, the following code runs fine:

protocol P { var p: String { get } }
struct S: P { let p="hello world" }

protocol Q {
  associatedtype A
  func f(a: A)
}

struct R: Q {
  typealias A = S
  func f(a: S) { print(a.p) }
}

let r = R()
r.f(a: S()) // Output: hello world

Reading SE-0346 section "Other positions", I thought I should be able to use the new constrained protocol syntax with the primary associated type A as in:

protocol Q<A> {
  associatedtype A
  func f(a: A)
}

struct R: Q<S> {
  //typealias A = S
  func f(a: S) { print(a.p) }
}

but Xcode gave me the error message, "Cannot inherit from protocol type with generic argument 'Q<S>'" on the struct R: Q<S> line. Am I using the new syntax incorrectly? What's the correct usage? Thanks.

2 Likes

My apologies, this is not currently implemented because the behavior of a constrained protocol type here is slightly different than the other positions; as you guessed, it implies a type alias. We should make it work, so that

struct R: Q<S> {}

is equivalent to the second form with the commented out type alias:

struct R: Q {
  typealias A = S
}

In the meantime, you can write the second form.

3 Likes

Cool. Thanks for the clarification.

@Slava_Pestov Is this missing support tracked as an issue in GitHub currently?

3 Likes

@Slava_Pestov is this implemented in Swift 5.9? I think this makes it much easier to translate conformances to dependency injection, e.g.

struct R: Q<S> {}

is much easier to copy/paste as a generic constraint to a function:

function doThing(_ thing: some Q<S>)
1 Like