Typealiases inside protocols

Types cannot be nested in protocols:

protocol P {
  struct S {} // 🛑 Type 'S' cannot be nested in protocol 'P'
}

But typealiases can:

protocol P {
  typealias X = Int // OK
}

I can see how this can be useful but I'm confused by for example the following.

This compiles:

protocol P {
  typealias X = Int
}

extension P {
  typealias X = Bool
}

struct A: P {}

Though print(S.X.self) prints Int. I would have expected Bool.

But, since the following doesn't compile, I guess the previous example shouldn't compile either, right?

protocol P { // 🛑 No type for 'Self.X' can satisfy both 'Self.X == Bool' and 'Self.X == Int'
  typealias X = Int
// }

// extension P {
  typealias X = Bool // 🛑 Invalid redeclaration of 'X'
}

struct A: P {}

Another example:

protocol P {
  typealias X = Int
}

extension P where Self == B {
  typealias X = Bool
}

extension P where Self == C {
  typealias X = String
}

struct A: P {}
struct B: P {}
struct C: P {}

print(A.X.self)
print(B.X.self)
print(C.X.self)

I would expect this to print:

Int
Bool
String

But all three prints Int ... :thinking:

What is the intended behavior here?

(I'm using Swift 5.7, not aware of any changes related to this.)

5 Likes

I am seeing the same thing.

Shouldn't redeclaring a typealias inside a protocol extension produce an error?

protocol P {
    typealias X = Int
}

extension P {
    typealias X = Bool // Ok!
}

typealias X = Int
typealias X = Bool // error: Invalid redeclaration of 'X'
2 Likes

@Jens can you file a GitHub issue and link it here?

Agree with @ibex10 it should probably be an error, but the whole thing is underspecified and I don't think much attention has been paid to it. Would probably necessitate a new language mode before it can be redone properly. Related (but not the same) bugs: