How to dynamically check if a type conforms to value of type?

If I have a value of Any.Type, is there a way to check if a type T conforms?

For example, if I have a type, and a type as a value:

struct MyError: Error {}

let errorType: Any.Type = Error.self

I want to check if MyError conforms to errorType.

The is operator is out of the question, since I merely have a value, and the scopes don't match:

MyError.self is errorType

:stop_sign: Cannot find type 'errorType' in scope

I was hoping I could prod the Any existential using _openExistential, but this doesn't return the right thing:

func conforms<T>(to type: T.Type) -> Bool {
  return MyError.self is T.Type
}

_openExistential(errorType, do: conforms(to:))
// returns false

// vs.

MyError.self is Error.Type
// returns true

Am I missing something subtle here? Or is there an entirely different way of accomplishing the same thing?

1 Like

For protocol types, substituting into a generic parameter T in T.Type can only give you the concrete metatype for the protocol, Error.Protocol, and not what you want, the existential metatype Error.Type. Inside conforms(to:), you're really asking MyError.self is Error.Protocol, which is false because only Error.self is an instance of Error.Protocol. You will need to bind T to the entire existential metatype Error.Type in order to do the test you want; something like this:


func conforms<T>(to type: T.Type) -> Bool {
    print(T.self)
  return MyError.self is T
}

let errorType: Any.Type = Error.Type.self

struct MyError: Error {}

print(_openExistential(errorType, do: conforms(to:)))
4 Likes

Thanks for the explanation!

In the context I'm working in, though, I already have a value of Error.Protocol. Is there any way to dynamically get an Error.Type.Protocol out of that? (type(of: errorType) yields an Error.Protocol.Type, which makes sense but isn't helpful.

I was working with metadata layout earlier (using Echo as a reference), but it's doing some funny things in C to populate protocol conformance data, which is complexity I was hoping to avoid.

There is no real protocol polymorphism in Swift right now, so there isn't a way to get from P to P.Type within the confines of the language itself. You would have to use the runtime yourself to do the dynamic protocol tests.

1 Like