-
Notifications
You must be signed in to change notification settings - Fork 22
[SoM] Functions that return protocol list types that throw will fail #22
Description
Dear Future Steve,
The problem is that in order to marshal something that contains a SwiftExistentialContainer, we need to know the size/stride of it. We can get this, but if SwiftExistentialContainer is embedded in a tuple, for example, we can't get its size using swift. We could hack in code to manually handle tuples (we did before, but it's gone now), but if anyone tries to call Metatypeof on a tuple containing one of these, it will fail. Sorry.
So what do we do?
We do a sleazy hack. We redefine all the SwiftExistentialContainer types to come in pairs:
SwiftExistentialContainerN which will be the existing SwiftExistentialContainerN structs and SwiftExistentialContainer<TIf0, ... TIfN>. Each of the generic versions would delegate to a non generic within it:
public SwiftExistentialContainer<TIf0> : ISwiftExistentialContainer {
public SwiftExistentialContainer1 Container { get; set; }
public Data0 { get { return Container.Data0 } set { Container.Data0 = value; } }
// etc
}
Next step is to change SwiftProtocolTypeAttribute to contain the library that defines the protocol (string) and the symbol for the protocol descriptor for that protocol. These symbols end in Mp in the mangling and do get picked up in the ProtocolContents when demangling a library. Add some helper methods to do the following:
- Get the
ProtocolDescriptorfor a type by getting itsSwiftProtocolTypeAttributeand using the library and symbol to get the handle. - Cache the protocol descriptor in the attribute.
Rewrite the various existential container factories to take a type list of the protocols they are binding to. Look at the Tuple code in StructMarshal for how to do this (basically, it's a switch with a bunch of typeof(SwiftExistentialContainer<,,,>).MakeType (types) to get the type object and then use reflection to get the default constructor.
Make all pinvokes take a ref to the non-generic version of any given container and make the local variables used for marshaling the strongly typed version which passes in its inner container.
Yes, this touches a lot of things, but the good news is that it will let us call Metatypeof on a generic existential container and do something useful with it.
Now comes the bad news (ish). For virtual methods that come in with one of these, I don't think we'll have any idea what the types are in any useful way. I mean maybe? They're going to be some interesting pinvoke callbacks, that's for sure.