I don't know why would you want that, but with generalized existentials this and many other exotics things would be possible:
protocol Object {
associatedtype Id
var id: Id { get }
}
protocol Vehicle: Object {
}
struct Car: Vehicle {
struct Id { ... }
let id: Id
}
func registerVehicleId(_ id: any<T> T.Id where T: Vehicle) {
let <V> openedID: V.Id = id
print(V.self) // prints "Car"
print(type(of: id)) // prints "Car.Id"
}
let car: Car = ...
registerVehicleId(car.id)
Note that such type would have a layout that stores value of identifier in the value buffer, but does store its type directly. Instead it stores types that existential type abstracts over - type T
and witness table of T: Vehicle
. When opening such existential you would get the full type T
.
And when passing id
to type(of:)
it is casted to Any
which has a different layout - value buffer and metadata for the actual type of the id
. So type(of:)
works as usual, but instead at the call site of type(of:)
compiler would emit code that takes type metadata for T
from existential, uses it to lookup metadata for the associated type, and then constructs Any
with that metadata.