May existential containers contain existential containers

Hello fellow Swift enthusiasts,

It is my understanding that if you type a variable with a protocol, then it will be emitted as an existential container. For instance, I would assume x to be an existential container in the following code:

protocol A {}
struct S: A {}
let x: A = S()

Assuming my understanding is correct, I was wondering what happens when one assigns an existential container to another existential container. In particular, I wonder if this would result in an existential containing the original container, or if it is reasonable to assume that there can never be nested levels of existential containers.

In other words, is y an existential that contains an instance of S, or an existential that contains an existential containing an instance of S in the following code:

protocol A {}
protocol B: A {}
struct S: B {}
let x: B = S()
let y: A = x

As a subsequent question, I would like to know how I could have answer that by myself. Could this be understood by looking at SIL, or should I go deeper and look at LLVM IR?

It is possible to stack up existential containers, say by repeatedly calling this function:

func wrap<T>(x: T) -> Any { return x }

return wrap(wrap(wrap(1)))

because Any is a valid binding for T, and the conversion from Any wraps the value. The runtime generally deals with this wrapping automatically, since things like dynamic casts will automatically look through multiple levels of existential container.

5 Likes
Terms of Service

Privacy Policy

Cookie Policy