Skip to content

Commit d093fcb

Browse files
committed
Reflection: Decode imported Objective-C classes and protocols as their own TypeRef
Right now we expect that every class and protocol has a field descriptor that tells us if the entity is @objc or not. For imported types, the descriptor will not exist if we did not directly emit a field whose concrete type contains the imported type. For example, in lldb, we might have a generic type whose runtime substituted type includes an imported type. In this case, TypeLowering would fail to produce a layout because it did not find a field descriptor for the imported type. A better approach is to have the TypeDecoder call a different factory method for imported types, and handle them specially in TypeLowering, bypassing the field type metadata altogether.
1 parent 5655b35 commit d093fcb

File tree

11 files changed

+228
-103
lines changed

11 files changed

+228
-103
lines changed

include/swift/Demangling/TypeDecoder.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "swift/Demangling/Demangler.h"
2323
#include "swift/Basic/LLVM.h"
2424
#include "swift/Runtime/Unreachable.h"
25+
#include "swift/Strings.h"
2526
#include <vector>
2627

2728
namespace swift {
@@ -75,6 +76,34 @@ class FunctionParam {
7576
}
7677
};
7778

79+
80+
#if SWIFT_OBJC_INTEROP
81+
/// For a mangled node that refers to an Objective-C class or protocol,
82+
/// return the class or protocol name.
83+
static inline Optional<StringRef> getObjCClassOrProtocolName(
84+
const Demangle::NodePointer &node) {
85+
if (node->getKind() != Demangle::Node::Kind::Class &&
86+
node->getKind() != Demangle::Node::Kind::Protocol)
87+
return None;
88+
89+
if (node->getNumChildren() != 2)
90+
return None;
91+
92+
// Check whether we have the __ObjC module.
93+
auto moduleNode = node->getChild(0);
94+
if (moduleNode->getKind() != Demangle::Node::Kind::Module ||
95+
moduleNode->getText() != MANGLING_MODULE_OBJC)
96+
return None;
97+
98+
// Check whether we have an identifier.
99+
auto nameNode = node->getChild(1);
100+
if (nameNode->getKind() != Demangle::Node::Kind::Identifier)
101+
return None;
102+
103+
return nameNode->getText();
104+
}
105+
#endif
106+
78107
/// Decode a mangled type to construct an abstract type, forming such
79108
/// types by invoking a custom builder.
80109
template <typename BuilderType>
@@ -112,6 +141,13 @@ class TypeDecoder {
112141

113142
return decodeMangledType(Node->getChild(0));
114143
case NodeKind::Class:
144+
{
145+
#if SWIFT_OBJC_INTEROP
146+
if (auto mangledName = getObjCClassOrProtocolName(Node))
147+
return Builder.createObjCClassType(mangledName->str());
148+
#endif
149+
LLVM_FALLTHROUGH;
150+
}
115151
case NodeKind::Enum:
116152
case NodeKind::Structure:
117153
case NodeKind::TypeAlias: // This can show up for imported Clang decls.
@@ -125,6 +161,14 @@ class TypeDecoder {
125161
return Builder.createNominalType(typeDecl, parent);
126162
}
127163
case NodeKind::BoundGenericClass:
164+
{
165+
#if SWIFT_OBJC_INTEROP
166+
if (Node->getNumChildren() == 2)
167+
if (auto mangledName = getObjCClassOrProtocolName(Node->getChild(0)))
168+
return Builder.createObjCClassType(mangledName->str());
169+
#endif
170+
LLVM_FALLTHROUGH;
171+
}
128172
case NodeKind::BoundGenericEnum:
129173
case NodeKind::BoundGenericStructure:
130174
case NodeKind::BoundGenericOtherNominalType: {
@@ -528,6 +572,11 @@ class TypeDecoder {
528572
&& node->getKind() != NodeKind::ProtocolSymbolicReference)
529573
return BuiltProtocolDecl();
530574

575+
#if SWIFT_OBJC_INTEROP
576+
if (auto objcProtocolName = getObjCClassOrProtocolName(node))
577+
return Builder.createObjCProtocolDecl(objcProtocolName->str());
578+
#endif
579+
531580
return Builder.createProtocolDecl(node);
532581
}
533582

include/swift/Reflection/TypeRef.h

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -386,11 +386,11 @@ class FunctionTypeRef final : public TypeRef {
386386
};
387387

388388
class ProtocolCompositionTypeRef final : public TypeRef {
389-
std::vector<const NominalTypeRef *> Protocols;
389+
std::vector<const TypeRef *> Protocols;
390390
const TypeRef *Superclass;
391391
bool HasExplicitAnyObject;
392392

393-
static TypeRefID Profile(std::vector<const NominalTypeRef *> Protocols,
393+
static TypeRefID Profile(std::vector<const TypeRef *> Protocols,
394394
const TypeRef *Superclass,
395395
bool HasExplicitAnyObject) {
396396
TypeRefID ID;
@@ -403,7 +403,7 @@ class ProtocolCompositionTypeRef final : public TypeRef {
403403
}
404404

405405
public:
406-
ProtocolCompositionTypeRef(std::vector<const NominalTypeRef *> Protocols,
406+
ProtocolCompositionTypeRef(std::vector<const TypeRef *> Protocols,
407407
const TypeRef *Superclass,
408408
bool HasExplicitAnyObject)
409409
: TypeRef(TypeRefKind::ProtocolComposition),
@@ -412,13 +412,14 @@ class ProtocolCompositionTypeRef final : public TypeRef {
412412

413413
template <typename Allocator>
414414
static const ProtocolCompositionTypeRef *
415-
create(Allocator &A, std::vector<const NominalTypeRef *> Protocols,
415+
create(Allocator &A, std::vector<const TypeRef *> Protocols,
416416
const TypeRef *Superclass, bool HasExplicitAnyObject) {
417417
FIND_OR_CREATE_TYPEREF(A, ProtocolCompositionTypeRef, Protocols,
418418
Superclass, HasExplicitAnyObject);
419419
}
420420

421-
const std::vector<const NominalTypeRef *> &getProtocols() const {
421+
// These are either NominalTypeRef or ObjCProtocolTypeRef.
422+
const std::vector<const TypeRef *> &getProtocols() const {
422423
return Protocols;
423424
}
424425

@@ -633,6 +634,36 @@ class ObjCClassTypeRef final : public TypeRef {
633634
}
634635
};
635636

637+
class ObjCProtocolTypeRef final : public TypeRef {
638+
std::string Name;
639+
static const ObjCProtocolTypeRef *UnnamedSingleton;
640+
641+
static TypeRefID Profile(const std::string &Name) {
642+
TypeRefID ID;
643+
ID.addString(Name);
644+
return ID;
645+
}
646+
public:
647+
ObjCProtocolTypeRef(const std::string &Name)
648+
: TypeRef(TypeRefKind::ObjCProtocol), Name(Name) {}
649+
650+
static const ObjCProtocolTypeRef *getUnnamed();
651+
652+
template <typename Allocator>
653+
static const ObjCProtocolTypeRef *create(Allocator &A,
654+
const std::string &Name) {
655+
FIND_OR_CREATE_TYPEREF(A, ObjCProtocolTypeRef, Name);
656+
}
657+
658+
const std::string &getName() const {
659+
return Name;
660+
}
661+
662+
static bool classof(const TypeRef *TR) {
663+
return TR->getKind() == TypeRefKind::ObjCProtocol;
664+
}
665+
};
666+
636667
class OpaqueTypeRef final : public TypeRef {
637668
static const OpaqueTypeRef *Singleton;
638669

include/swift/Reflection/TypeRefBuilder.h

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ class TypeRefBuilder {
160160
public:
161161
using BuiltType = const TypeRef *;
162162
using BuiltNominalTypeDecl = Optional<std::string>;
163-
using BuiltProtocolDecl = Optional<std::string>;
163+
using BuiltProtocolDecl = Optional<std::pair<std::string, bool /*isObjC*/>>;
164164

165165
TypeRefBuilder();
166166

@@ -214,9 +214,14 @@ class TypeRefBuilder {
214214
return Demangle::mangleNode(node);
215215
}
216216

217-
Optional<std::string>
217+
BuiltProtocolDecl
218218
createProtocolDecl(const Demangle::NodePointer &node) {
219-
return Demangle::mangleNode(node);
219+
return std::make_pair(Demangle::mangleNode(node), false);
220+
}
221+
222+
BuiltProtocolDecl
223+
createObjCProtocolDecl(std::string &&name) {
224+
return std::make_pair(name, true);
220225
}
221226

222227
Optional<std::string> createNominalTypeDecl(std::string &&mangledName) {
@@ -265,9 +270,15 @@ class TypeRefBuilder {
265270
createProtocolCompositionType(ArrayRef<BuiltProtocolDecl> protocols,
266271
BuiltType superclass,
267272
bool isClassBound) {
268-
std::vector<const NominalTypeRef *> protocolRefs;
273+
std::vector<const TypeRef *> protocolRefs;
269274
for (const auto &protocol : protocols) {
270-
protocolRefs.push_back(createNominalType(protocol));
275+
if (!protocol)
276+
continue;
277+
278+
if (protocol->second)
279+
protocolRefs.push_back(createObjCProtocolType(protocol->first));
280+
else
281+
protocolRefs.push_back(createNominalType(protocol->first));
271282
}
272283

273284
return ProtocolCompositionTypeRef::create(*this, protocolRefs, superclass,
@@ -292,8 +303,12 @@ class TypeRefBuilder {
292303
const DependentMemberTypeRef *
293304
createDependentMemberType(const std::string &member,
294305
const TypeRef *base,
295-
Optional<std::string> protocol) {
296-
return DependentMemberTypeRef::create(*this, member, base, *protocol);
306+
BuiltProtocolDecl protocol) {
307+
// Objective-C protocols don't have dependent types.
308+
if (protocol->second)
309+
return nullptr;
310+
return DependentMemberTypeRef::create(*this, member, base,
311+
protocol->first);
297312
}
298313

299314
#define REF_STORAGE(Name, ...) \
@@ -306,13 +321,18 @@ class TypeRefBuilder {
306321
return SILBoxTypeRef::create(*this, base);
307322
}
308323

324+
const ObjCClassTypeRef *getUnnamedObjCClassType() {
325+
return createObjCClassType("");
326+
}
327+
309328
const ObjCClassTypeRef *
310-
createObjCClassType(const std::string &mangledName) {
311-
return ObjCClassTypeRef::create(*this, mangledName);
329+
createObjCClassType(const std::string &name) {
330+
return ObjCClassTypeRef::create(*this, name);
312331
}
313332

314-
const ObjCClassTypeRef *getUnnamedObjCClassType() {
315-
return createObjCClassType("");
333+
const ObjCProtocolTypeRef *
334+
createObjCProtocolType(const std::string &name) {
335+
return ObjCProtocolTypeRef::create(*this, name);
316336
}
317337

318338
const ForeignClassTypeRef *

include/swift/Reflection/TypeRefs.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ TYPEREF(GenericTypeParameter, TypeRef)
2828
TYPEREF(DependentMember, TypeRef)
2929
TYPEREF(ForeignClass, TypeRef)
3030
TYPEREF(ObjCClass, TypeRef)
31+
TYPEREF(ObjCProtocol, TypeRef)
3132
TYPEREF(Opaque, TypeRef)
3233
#define REF_STORAGE(Name, ...) \
3334
TYPEREF(Name##Storage, TypeRef)

include/swift/Remote/MetadataReader.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,8 @@ class MetadataReader {
509509
if (!Demangled)
510510
return BuiltType();
511511

512+
// FIXME: Imported protocols?
513+
512514
auto Protocol = Builder.createProtocolDecl(Demangled);
513515
if (!Protocol)
514516
return BuiltType();

lib/RemoteAST/RemoteAST.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,16 @@ class RemoteASTTypeBuilder {
438438
return createNominalType(typeDecl, /*parent*/ Type());
439439
}
440440

441+
ProtocolDecl *createObjCProtocolDecl(StringRef name) {
442+
auto typeDecl =
443+
findForeignNominalTypeDecl(name, /*relatedEntityKind*/{},
444+
ForeignModuleKind::Imported,
445+
Demangle::Node::Kind::Protocol);
446+
if (auto *protocolDecl = dyn_cast_or_null<ProtocolDecl>(typeDecl))
447+
return protocolDecl;
448+
return nullptr;
449+
}
450+
441451
Type createForeignClassType(StringRef mangledName) {
442452
auto typeDecl = createNominalTypeDecl(mangledName);
443453
if (!typeDecl) return Type();

stdlib/public/Reflection/TypeLowering.cpp

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ BuiltinTypeInfo::BuiltinTypeInfo(const BuiltinTypeDescriptor *descriptor)
197197
/// Utility class for building values that contain witness tables.
198198
class ExistentialTypeInfoBuilder {
199199
TypeConverter &TC;
200-
std::vector<const NominalTypeRef *> Protocols;
200+
std::vector<const TypeRef *> Protocols;
201201
const TypeRef *Superclass = nullptr;
202202
ExistentialTypeRepresentation Representation;
203203
ReferenceCounting Refcounting;
@@ -218,8 +218,9 @@ class ExistentialTypeInfoBuilder {
218218
return false;
219219

220220
for (auto *P : Protocols) {
221-
if (P->isErrorProtocol())
222-
return true;
221+
if (auto *NTD = dyn_cast<NominalTypeRef>(P))
222+
if (NTD->isErrorProtocol())
223+
return true;
223224
}
224225
return false;
225226
}
@@ -232,6 +233,20 @@ class ExistentialTypeInfoBuilder {
232233
}
233234

234235
for (auto *P : Protocols) {
236+
auto *NTD = dyn_cast<NominalTypeRef>(P);
237+
auto *OP = dyn_cast<ObjCProtocolTypeRef>(P);
238+
if (!NTD && !OP) {
239+
DEBUG_LOG(std::cerr << "Bad protocol: "; P->dump())
240+
Invalid = true;
241+
continue;
242+
}
243+
244+
// Don't look up field info for imported Objective-C protocols.
245+
if (OP) {
246+
ObjC = true;
247+
continue;
248+
}
249+
235250
std::pair<const FieldDescriptor *, const ReflectionInfo *> FD =
236251
TC.getBuilder().getFieldTypeInfo(P);
237252
if (FD.first == nullptr) {
@@ -270,7 +285,7 @@ class ExistentialTypeInfoBuilder {
270285
ObjC(false), WitnessTableCount(0),
271286
Invalid(false) {}
272287

273-
void addProtocol(const NominalTypeRef *P) {
288+
void addProtocol(const TypeRef *P) {
274289
Protocols.push_back(P);
275290
}
276291

@@ -286,11 +301,19 @@ class ExistentialTypeInfoBuilder {
286301
// Anything else should either be a superclass constraint, or
287302
// we have an invalid typeref.
288303
if (!isa<NominalTypeRef>(T) &&
289-
!isa<BoundGenericTypeRef>(T)) {
304+
!isa<BoundGenericTypeRef>(T) &&
305+
!isa<ObjCClassTypeRef>(T)) {
290306
DEBUG_LOG(std::cerr << "Bad existential member: "; T->dump())
291307
Invalid = true;
292308
return;
293309
}
310+
311+
// Don't look up field info for imported Objective-C classes.
312+
if (auto *OC = dyn_cast<ObjCClassTypeRef>(T)) {
313+
addAnyObject();
314+
return;
315+
}
316+
294317
const auto &FD = TC.getBuilder().getFieldTypeInfo(T);
295318
if (FD.first == nullptr) {
296319
DEBUG_LOG(std::cerr << "No field descriptor: "; T->dump())
@@ -721,6 +744,10 @@ class HasFixedSize
721744
return true;
722745
}
723746

747+
bool visitObjCProtocolTypeRef(const ObjCProtocolTypeRef *OP) {
748+
return true;
749+
}
750+
724751
#define REF_STORAGE(Name, ...) \
725752
bool \
726753
visit##Name##StorageTypeRef(const Name##StorageTypeRef *US) { \
@@ -848,6 +875,10 @@ class HasSingletonMetatype
848875
return MetatypeRepresentation::Unknown;
849876
}
850877

878+
MetatypeRepresentation visitObjCProtocolTypeRef(const ObjCProtocolTypeRef *OP) {
879+
return MetatypeRepresentation::Unknown;
880+
}
881+
851882
#define REF_STORAGE(Name, ...) \
852883
MetatypeRepresentation \
853884
visit##Name##StorageTypeRef(const Name##StorageTypeRef *US) { \
@@ -1197,6 +1228,11 @@ class LowerType
11971228
ReferenceCounting::Unknown);
11981229
}
11991230

1231+
const TypeInfo *visitObjCProtocolTypeRef(const ObjCProtocolTypeRef *OP) {
1232+
return TC.getReferenceTypeInfo(ReferenceKind::Strong,
1233+
ReferenceCounting::Unknown);
1234+
}
1235+
12001236
// Apply a storage qualifier, like 'weak', 'unowned' or 'unowned(unsafe)'
12011237
// to a type with reference semantics, such as a class reference or
12021238
// class-bound existential.

0 commit comments

Comments
 (0)