I'm writing tests for calling the Metadata Access Function on some types, and surprisingly one of the tests failed because the type metadata had different pointers. Consider the following:
// I just need the dictionary descriptor
let metadata = reflectStruct([String: Int].self)!
let accessor = metadata.descriptor.accessor
let response = accessor(.complete, Int.self, Double.self)
print(response.type) // Swift.Dictionary<Swift.Int, Swift.Double>
XCTAssert(response.type == [Int: Double].self) // Assertion hit!
I was surprised because I thought all metadata was unique and a type only had a single metadata record. I did some more playing around and managed to crash the runtime:
print([Int: Double].self)
let response = accessor(.complete, Int.self, Double.self) // Crash!
Relevant Backtrace:
frame #0: 0x00007fff2cebaad5 libswiftCore.dylib`swift::MetadataCacheKey::compareProtocolConformanceDescriptors(swift::TargetProtocolConformanceDescriptor<swift::InProcess> const*, swift::TargetProtocolConformanceDescriptor<swift::InProcess> const*) + 21
frame #1: 0x00007fff2ceb0a16 libswiftCore.dylib`_swift_getGenericMetadata(swift::MetadataRequest, void const* const*, swift::TargetTypeContextDescriptor<swift::InProcess> const*) + 502
frame #2: 0x00007fff2ce8a9c0 libswiftCore.dylib`__swift_instantiateCanonicalPrespecializedGenericMetadata + 32
* frame #3: 0x0000000102b2988a EchoTests`echo_callAccessor2(ptr=0x00007fff2ce49f70, request=0, arg0=0x00007fff815257e0, arg1=0x00007fff81525440) at CallAccessor.c:47:10
Interestingly though, this only occurs on types who use __swift_instantiateCanonicalPrespecializedGenericMetadata in their metadata accessor (I've only tested dictionary). Other accessors who don't use this prespecialization stub pass the assertion and don't crash if I print them before:
struct Foo<T, U> {}
let metadata = ...
let accessor = ...
print(Foo<Int, Int>.self)
let response = accessor(.complete, Int.self, Int.self) // no crash
XCTAssert(response.type == Foo<Int, Int>.self) // no assertion
Am I doing something wrong, or could there possibly be an issue in the compiler/runtime somewhere?
cc: @John_McCall @nate_chandler (who implemented metadata prespecialization)