Following from this thread, a related question—find it in the topic title.
This compiles:
protocol P { }
enum E1: P { }
enum E2: P { }
protocol SDelegate<T> {
associatedtype T: P
}
struct S<T: P> {
static var delegateType: any SDelegate.Type {
switch T.self {
case let e1Type as E1.Type: S<E1>.SE1.self
case let e2Type as E2.Type: S<E2>.SE2.self
default: fatalError()
}
}
}
extension S<E1> { enum SE1: SDelegate { } }
extension S<E2> { enum SE2: SDelegate { } }
It doesn’t compile, with the addition of this <T>:
struct S<T: P> {
static var delegateType: any SDelegate<T>.Type {
switch T.self {
case let e1Type as E1.Type: S<E1>.SE1.self
case let e2Type as E2.Type: S<E2>.SE2.self
default: fatalError()
}
}
}
I understand why. What are you supposed to do when you want a more constrained translation of a metatype?
Note: I don’t actually want to have to use existentials, and this switching over a known set of types. Please, please tell me how to avoid that without the associatedtypes from the other thread.
Thank you. That's what I came up with later as well. I don't think it's possible without using an intermediate result (delegateType, here), without force casting at the end of the line of every case?:
let delegateType: any SDelegate.Type = switch T.self {
case let e1Type as E1.Type: S<E1>.SE1.self
case let e2Type as E2.Type: S<E2>.SE2.self
default: fatalError()
}
return delegateType as! any SDelegate<_>.Type
No, the T here is an associated type of SDelegate, not an SDelegate itself. (Following from the other thread, this is a reversal of each P having an associated type which conforms to SDelegate.)
For complex metadata type manipulation, another approach on ABI-stable Darwin platforms is to retrieve the corresponding data directly from the Runtime.
Also inspired by a private framework, I’ve wrapped and exposed such ability as the OpenGraph.Metadata API. If you’d prefer not to build the Swift Toolchain locally, I also provide a prebuilt xcframework version if you want to quickly try it.