Skip to content

Commit 60dff01

Browse files
committed
Reflection: Simplify associated type metadata emission
Instead of hooking into nominal type and extension emission and walking all conformances of those declarations, let's just directly hook into the logic for emitting conformances. This fixes an issue where we would apparently emit duplicate conformances, as well as unnecessary conformances that are defined elsewhere.
1 parent 7a46b0f commit 60dff01

File tree

8 files changed

+46
-118
lines changed

8 files changed

+46
-118
lines changed

lib/IRGen/GenClass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -773,7 +773,7 @@ void IRGenModule::emitClassDecl(ClassDecl *D) {
773773
classTI.getLayout(*this, selfType),
774774
classTI.getClassLayout(*this, selfType));
775775
emitNestedTypeDecls(D->getMembers());
776-
emitReflectionMetadata(D);
776+
emitFieldMetadataRecord(D);
777777
}
778778

779779
namespace {

lib/IRGen/GenDecl.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2055,6 +2055,8 @@ llvm::Constant *IRGenModule::emitProtocolConformances() {
20552055

20562056
SmallVector<llvm::Constant*, 8> elts;
20572057
for (auto *conformance : ProtocolConformances) {
2058+
emitAssociatedTypeMetadataRecord(conformance);
2059+
20582060
auto descriptorRef = getAddrOfLLVMVariableOrGOTEquivalent(
20592061
LinkEntity::forProtocolDescriptor(conformance->getProtocol()),
20602062
getPointerAlignment(), ProtocolDescriptorStructTy);
@@ -2757,7 +2759,6 @@ static bool shouldEmitCategory(IRGenModule &IGM, ExtensionDecl *ext) {
27572759
}
27582760

27592761
void IRGenModule::emitExtension(ExtensionDecl *ext) {
2760-
emitAssociatedTypeMetadataRecord(ext);
27612762
emitNestedTypeDecls(ext->getMembers());
27622763

27632764
// Generate a category if the extension either introduces a

lib/IRGen/GenEnum.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5562,7 +5562,7 @@ const TypeInfo *TypeConverter::convertEnumType(TypeBase *key, CanType type,
55625562
void IRGenModule::emitEnumDecl(EnumDecl *theEnum) {
55635563
emitEnumMetadata(*this, theEnum);
55645564
emitNestedTypeDecls(theEnum->getMembers());
5565-
emitReflectionMetadata(theEnum);
5565+
emitFieldMetadataRecord(theEnum);
55665566
}
55675567

55685568
void irgen::emitSwitchAddressOnlyEnumDispatch(IRGenFunction &IGF,

lib/IRGen/GenMeta.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5694,7 +5694,7 @@ void IRGenModule::emitProtocolDecl(ProtocolDecl *protocol) {
56945694
var->setConstant(true);
56955695
var->setInitializer(init);
56965696

5697-
emitReflectionMetadata(protocol);
5697+
emitFieldMetadataRecord(protocol);
56985698
}
56995699

57005700
/// \brief Load a reference to the protocol descriptor for the given protocol.

lib/IRGen/GenReflection.cpp

Lines changed: 39 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -227,39 +227,24 @@ class ReflectionMetadataBuilder : public ConstantBuilder<> {
227227
class AssociatedTypeMetadataBuilder : public ReflectionMetadataBuilder {
228228
static const uint32_t AssociatedTypeRecordSize = 8;
229229

230-
llvm::PointerUnion<const NominalTypeDecl *, const ExtensionDecl *>
231-
NominalOrExtensionDecl;
230+
const ProtocolConformance *Conformance;
231+
ArrayRef<std::pair<StringRef, CanType>> AssociatedTypes;
232232

233-
void addConformance(Module *ModuleContext,
234-
CanType ConformingType,
235-
const ProtocolConformance *Conformance) {
236-
SmallVector<std::pair<StringRef, CanType>, 2> AssociatedTypes;
237-
238-
auto collectTypeWitness = [&](const AssociatedTypeDecl *AssocTy,
239-
const Substitution &Sub,
240-
const TypeDecl *TD) -> bool {
241-
242-
auto Subst = ArchetypeBuilder::mapTypeOutOfContext(
243-
Conformance->getDeclContext(), Sub.getReplacement());
244-
245-
AssociatedTypes.push_back({
246-
AssocTy->getNameStr(),
247-
Subst->getCanonicalType()
248-
});
249-
return false;
250-
};
233+
void layout() {
234+
// If the conforming type is generic, we just want to emit the
235+
// unbound generic type here.
236+
auto *Nominal = Conformance->getInterfaceType()->getAnyNominal();
237+
assert(Nominal && "Structural conformance?");
251238

252-
Conformance->forEachTypeWitness(/*resolver*/ nullptr, collectTypeWitness);
239+
PrettyStackTraceDecl DebugStack("emitting associated type metadata",
240+
Nominal);
253241

254-
// If there are no associated types, don't bother emitting any
255-
// metadata.
256-
if (AssociatedTypes.empty())
257-
return;
242+
auto *M = IGM.getSILModule().getSwiftModule();
258243

259-
addTypeRef(ModuleContext, ConformingType);
244+
addTypeRef(M, Nominal->getDeclaredType()->getCanonicalType());
260245

261246
auto ProtoTy = Conformance->getProtocol()->getDeclaredType();
262-
addTypeRef(ModuleContext, ProtoTy->getCanonicalType());
247+
addTypeRef(M, ProtoTy->getCanonicalType());
263248

264249
addConstantInt32(AssociatedTypes.size());
265250
addConstantInt32(AssociatedTypeRecordSize);
@@ -268,47 +253,16 @@ class AssociatedTypeMetadataBuilder : public ReflectionMetadataBuilder {
268253
auto NameGlobal = IGM.getAddrOfStringForTypeRef(AssocTy.first);
269254
addRelativeAddress(NameGlobal);
270255
addBuiltinTypeRefs(AssocTy.second);
271-
addTypeRef(ModuleContext, AssocTy.second);
272-
}
273-
}
274-
275-
const NominalTypeDecl *getNominalTypeDecl() const {
276-
return NominalOrExtensionDecl.dyn_cast<const NominalTypeDecl *>();
277-
}
278-
279-
const ExtensionDecl *getExtensionDecl() const {
280-
return NominalOrExtensionDecl.dyn_cast<const ExtensionDecl *>();
281-
}
282-
283-
void layout() {
284-
if (auto Decl = getNominalTypeDecl()) {
285-
PrettyStackTraceDecl DebugStack("emitting associated type metadata",
286-
Decl);
287-
for (auto Conformance : Decl->getAllConformances()) {
288-
if (Conformance->isIncomplete())
289-
continue;
290-
addConformance(Decl->getModuleContext(),
291-
Decl->getDeclaredType()->getCanonicalType(),
292-
Conformance);
293-
}
294-
} else if (auto Ext = getExtensionDecl()) {
295-
PrettyStackTraceDecl DebugStack("emitting associated type metadata", Ext);
296-
for (auto Conformance : Ext->getLocalConformances()) {
297-
auto Decl = Ext->getExtendedType()->getNominalOrBoundGenericNominal();
298-
addConformance(Ext->getDeclContext()->getParentModule(),
299-
Decl->getDeclaredType()->getCanonicalType(),
300-
Conformance);
301-
}
256+
addTypeRef(M, AssocTy.second);
302257
}
303258
}
304259

305260
public:
306-
AssociatedTypeMetadataBuilder(IRGenModule &IGM, const NominalTypeDecl *Decl)
307-
: ReflectionMetadataBuilder(IGM), NominalOrExtensionDecl(Decl) {}
308-
309-
AssociatedTypeMetadataBuilder(IRGenModule &IGM, const ExtensionDecl *Decl)
310-
: ReflectionMetadataBuilder(IGM), NominalOrExtensionDecl(Decl) {}
311-
261+
AssociatedTypeMetadataBuilder(IRGenModule &IGM,
262+
const ProtocolConformance *Conformance,
263+
ArrayRef<std::pair<StringRef, CanType>> AssociatedTypes)
264+
: ReflectionMetadataBuilder(IGM), Conformance(Conformance),
265+
AssociatedTypes(AssociatedTypes) {}
312266

313267
llvm::GlobalVariable *emit() {
314268
auto tempBase = std::unique_ptr<llvm::GlobalVariable>(
@@ -848,29 +802,35 @@ IRGenModule::getAddrOfCaptureDescriptor(SILFunction &Caller,
848802
return llvm::ConstantExpr::getBitCast(var, CaptureDescriptorPtrTy);
849803
}
850804

851-
void IRGenModule::emitReflectionMetadata(const NominalTypeDecl *Decl) {
805+
void IRGenModule::
806+
emitAssociatedTypeMetadataRecord(const ProtocolConformance *Conformance) {
852807
if (!IRGen.Opts.EnableReflectionMetadata)
853808
return;
854809

855-
emitFieldMetadataRecord(Decl);
856-
emitAssociatedTypeMetadataRecord(Decl);
857-
}
810+
SmallVector<std::pair<StringRef, CanType>, 2> AssociatedTypes;
858811

859-
void IRGenModule::emitAssociatedTypeMetadataRecord(const NominalTypeDecl *Decl){
860-
if (!IRGen.Opts.EnableReflectionMetadata)
861-
return;
812+
auto collectTypeWitness = [&](const AssociatedTypeDecl *AssocTy,
813+
const Substitution &Sub,
814+
const TypeDecl *TD) -> bool {
862815

863-
AssociatedTypeMetadataBuilder builder(*this, Decl);
864-
auto var = builder.emit();
865-
if (var)
866-
addUsedGlobal(var);
867-
}
816+
auto Subst = ArchetypeBuilder::mapTypeOutOfContext(
817+
Conformance->getDeclContext(), Sub.getReplacement());
868818

869-
void IRGenModule::emitAssociatedTypeMetadataRecord(const ExtensionDecl *Ext) {
870-
if (!IRGen.Opts.EnableReflectionMetadata)
819+
AssociatedTypes.push_back({
820+
AssocTy->getNameStr(),
821+
Subst->getCanonicalType()
822+
});
823+
return false;
824+
};
825+
826+
Conformance->forEachTypeWitness(/*resolver*/ nullptr, collectTypeWitness);
827+
828+
// If there are no associated types, don't bother emitting any
829+
// metadata.
830+
if (AssociatedTypes.empty())
871831
return;
872832

873-
AssociatedTypeMetadataBuilder builder(*this, Ext);
833+
AssociatedTypeMetadataBuilder builder(*this, Conformance, AssociatedTypes);
874834
auto var = builder.emit();
875835
if (var)
876836
addUsedGlobal(var);

lib/IRGen/GenStruct.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -830,7 +830,7 @@ irgen::getPhysicalStructMemberAccessStrategy(IRGenModule &IGM,
830830
void IRGenModule::emitStructDecl(StructDecl *st) {
831831
emitStructMetadata(*this, st);
832832
emitNestedTypeDecls(st->getMembers());
833-
emitReflectionMetadata(st);
833+
emitFieldMetadataRecord(st);
834834
}
835835

836836
namespace {

lib/IRGen/IRGenModule.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -734,9 +734,7 @@ class IRGenModule {
734734
const HeapLayout &layout);
735735
llvm::Constant *getAddrOfBoxDescriptor(CanType boxedType);
736736

737-
void emitReflectionMetadata(const NominalTypeDecl *Decl);
738-
void emitAssociatedTypeMetadataRecord(const NominalTypeDecl *Decl);
739-
void emitAssociatedTypeMetadataRecord(const ExtensionDecl *Ext);
737+
void emitAssociatedTypeMetadataRecord(const ProtocolConformance *Conformance);
740738
void emitFieldMetadataRecord(const NominalTypeDecl *Decl);
741739
void emitBuiltinReflectionMetadata();
742740
std::string getBuiltinTypeMetadataSectionName();

test/Reflection/typeref_decoding.swift

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -594,22 +594,6 @@
594594
// CHECK: typealias Outer = A
595595
// CHECK: (generic_type_parameter depth=0 index=0)
596596

597-
// CHECK: - TypesToReflect.C4 : TypesToReflect.P1
598-
// CHECK: typealias Inner = A
599-
// CHECK: (generic_type_parameter depth=0 index=0)
600-
601-
// CHECK: - TypesToReflect.C4 : TypesToReflect.P2
602-
// CHECK: typealias Outer = A
603-
// CHECK: (generic_type_parameter depth=0 index=0)
604-
605-
// CHECK: - TypesToReflect.S4 : TypesToReflect.P1
606-
// CHECK: typealias Inner = A
607-
// CHECK: (generic_type_parameter depth=0 index=0)
608-
609-
// CHECK: - TypesToReflect.S4 : TypesToReflect.P2
610-
// CHECK: typealias Outer = A
611-
// CHECK: (generic_type_parameter depth=0 index=0)
612-
613597
// CHECK: - TypesToReflect.S4 : TypesToReflect.P1
614598
// CHECK: typealias Inner = A
615599
// CHECK: (generic_type_parameter depth=0 index=0)
@@ -633,21 +617,6 @@
633617
// CHECK: typealias Second = B
634618
// CHECK: (generic_type_parameter depth=0 index=1)
635619

636-
// CHECK: - TypesToReflect.E4 : TypesToReflect.P1
637-
// CHECK: typealias Inner = A
638-
// CHECK: (generic_type_parameter depth=0 index=0)
639-
640-
// CHECK: - TypesToReflect.E4 : TypesToReflect.P2
641-
// CHECK: typealias Outer = B
642-
// CHECK: (generic_type_parameter depth=0 index=1)
643-
644-
// CHECK: - TypesToReflect.E4 : TypesToReflect.P3
645-
// CHECK: typealias First = A
646-
// CHECK: (generic_type_parameter depth=0 index=0)
647-
648-
// CHECK: typealias Second = B
649-
// CHECK: (generic_type_parameter depth=0 index=1)
650-
651620
// CHECK: - TypesToReflect.S : TypesToReflect.P4
652621
// CHECK: typealias Result = Swift.Int
653622
// CHECK: (struct Swift.Int)

0 commit comments

Comments
 (0)