mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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:
@@ -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>
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
30
test/Runtime/demangleToMetadataObjC.swift
Normal file
30
test/Runtime/demangleToMetadataObjC.swift
Normal 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()
|
||||
|
||||
Reference in New Issue
Block a user