[Runtime] Lookup @objc protocols in mangled name -> type metadata function.

Swift-defined @objc protocols are registered with the Objective-C runtime
under the Swift 3 mangling scheme; look in the Objective-C runting using
objc_getProtocol() with the appropriate name.

Also, correctly compute the "class bound" bit when forming a protocol
composition metatype. The information isn't in the mangled name when it
can be recovered from the protocols themselves, so look at the protocols.
This commit is contained in:
Doug Gregor
2018-01-10 16:18:55 -08:00
parent 82140ca811
commit c302042dc5
4 changed files with 83 additions and 4 deletions

View File

@@ -2145,7 +2145,7 @@ struct TargetProtocolDescriptor {
/// The list of protocols this protocol refines.
ConstTargetMetadataPointer<Runtime, TargetProtocolDescriptorList>
InheritedProtocols;
InheritedProtocols;
/// Unused by the Swift runtime.
TargetPointer<Runtime, const void>

View File

@@ -2350,6 +2350,21 @@ ExistentialTypeMetadata::getWitnessTable(const OpaqueValue *container,
return witnessTables[i];
}
#ifndef NDEBUG
/// Determine whether any of the given protocols is class-bound.
static bool anyProtocolIsClassBound(
size_t numProtocols,
const ProtocolDescriptor * const *protocols) {
for (unsigned i = 0; i != numProtocols; ++i) {
if (protocols[i]->Flags.getClassConstraint()
== ProtocolClassConstraint::Class)
return true;
}
return false;
}
#endif
/// \brief Fetch a uniqued metadata for an existential type. The array
/// referenced by \c protocols will be sorted in-place.
const ExistentialTypeMetadata *
@@ -2364,6 +2379,11 @@ swift::swift_getExistentialTypeMetadata(
// swift_getExistentialTypeMetadata always sorts the `protocols` array using
// a globally stable ordering that's consistent across modules.
// Ensure that the "class constraint" bit is set whenever we have a
// superclass or a one of the protocols is class-bound.
assert(classConstraint == ProtocolClassConstraint::Class ||
(!superclassConstraint &&
!anyProtocolIsClassBound(numProtocols, protocols)));
ExistentialCacheEntry::Key key = {
superclassConstraint, classConstraint, numProtocols, protocols
};

View File

@@ -324,7 +324,24 @@ public:
BuiltProtocolDecl createProtocolDecl(
const Demangle::NodePointer &node) const {
auto mangledName = Demangle::mangleNode(node);
return _findProtocolDescriptor(mangledName);
// Look for a Swift protocol with this mangled name.
if (auto protocol = _findProtocolDescriptor(mangledName))
return protocol;
#if SWIFT_OBJC_INTEROP
// Look for a Swift-defined @objc protocol with the Swift 3 mangling that
// is used for Objective-C entities.
std::string objcMangledName =
"_TtP" + mangledName.substr(0, mangledName.size()-1) + "_";
if (auto protocol = objc_getProtocol(objcMangledName.c_str())) {
auto description = (ProtocolDescriptor *)(protocol);
assert(objcMangledName == description->Name);
return description;
}
#endif
return nullptr;
}
BuiltType createNominalType(BuiltNominalTypeDecl typeDecl,
@@ -365,8 +382,20 @@ public:
BuiltType createProtocolCompositionType(ArrayRef<BuiltProtocolDecl> protocols,
BuiltType superclass,
bool isClassBound) const {
auto classConstraint = isClassBound ? ProtocolClassConstraint::Class
: ProtocolClassConstraint::Any;
// Determine whether we have a class bound.
ProtocolClassConstraint classConstraint = ProtocolClassConstraint::Any;
if (isClassBound || superclass) {
classConstraint = ProtocolClassConstraint::Class;
} else {
for (auto protocol : protocols) {
if (protocol->Flags.getClassConstraint()
== ProtocolClassConstraint::Class) {
classConstraint = ProtocolClassConstraint::Class;
break;
}
}
}
return swift_getExistentialTypeMetadata(classConstraint, superclass,
protocols.size(), protocols.data());
}

View File

@@ -0,0 +1,30 @@
// RUN: %target-run-simple-swift
// REQUIRES: executable_test
// REQUIRES: objc_interop
import StdlibUnittest
import Foundation
let DemangleToMetadataTests = TestSuite("DemangleToMetadataObjC")
@objc class C : NSObject { }
@objc enum E: Int { case a }
@objc protocol P1 { }
DemangleToMetadataTests.test("@objc classes") {
expectEqual(type(of: C()), _typeByMangledName("4main1CC")!)
}
DemangleToMetadataTests.test("@objc enums") {
expectEqual(type(of: E.a), _typeByMangledName("4main1EO")!)
}
func f1_composition_objc_protocol(_: P1) { }
DemangleToMetadataTests.test("@objc protocols") {
expectEqual(type(of: f1_composition_objc_protocol),
_typeByMangledName("yy4main2P1_pc")!)
}
runAllTests()