Skip to content

Commit 4549fcd

Browse files
committed
[ABI] Add associated conformance descriptors.
Associated conformance descriptors are aliases that refer to associated conformance requirements within a protocol descriptor’s list of requirements. They will be used to provide protocol resilience against the addition of new associated conformance requirements (which only makes sense for newly-introduced, defaulted associated types).
1 parent ab61aae commit 4549fcd

File tree

16 files changed

+170
-20
lines changed

16 files changed

+170
-20
lines changed

include/swift/Demangling/DemangleNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ NODE(CurryThunk)
210210
NODE(DispatchThunk)
211211
NODE(MethodDescriptor)
212212
NODE(ProtocolRequirementsBaseDescriptor)
213+
NODE(AssociatedConformanceDescriptor)
213214
NODE(AssociatedTypeDescriptor)
214215
NODE(ThrowsAnnotation)
215216
NODE(EmptyList)

include/swift/IRGen/Linking.h

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,13 @@ class LinkEntity {
206206
/// The pointer is an AssociatedTypeDecl*.
207207
AssociatedTypeDescriptor,
208208

209+
/// An descriptor for an associated conformance within a protocol, which
210+
/// will alias the TargetProtocolRequirement descripting this
211+
/// particular associated conformance.
212+
/// The pointer is a ProtocolDecl*; the index of the associated conformance
213+
/// is stored in the data.
214+
AssociatedConformanceDescriptor,
215+
209216
/// A function which returns the default type metadata for the associated
210217
/// type of a protocol. The secondary pointer is a ProtocolDecl*.
211218
/// The index of the associated type declaration is stored in the data.
@@ -342,6 +349,21 @@ class LinkEntity {
342349
Data = LINKENTITY_SET_FIELD(Kind, unsigned(kind));
343350
}
344351

352+
void setForProtocolAndAssociatedConformance(Kind kind,
353+
const ProtocolDecl *proto,
354+
CanType associatedType,
355+
ProtocolDecl *associatedProtocol){
356+
assert(isDeclKind(kind));
357+
Pointer = static_cast<ValueDecl *>(const_cast<ProtocolDecl *>(proto));
358+
SecondaryPointer = nullptr;
359+
Data = LINKENTITY_SET_FIELD(Kind, unsigned(kind)) |
360+
LINKENTITY_SET_FIELD(AssociatedConformanceIndex,
361+
getAssociatedConformanceIndex(
362+
proto,
363+
associatedType,
364+
associatedProtocol));
365+
}
366+
345367
void setForProtocolConformance(Kind kind, const ProtocolConformance *c) {
346368
assert(isProtocolConformanceKind(kind) && !isTypeKind(kind));
347369
Pointer = nullptr;
@@ -407,14 +429,12 @@ class LinkEntity {
407429
}
408430

409431
// We store associated conformances using their index in the requirement
410-
// list of the requirement signature of the conformance's protocol.
411-
static unsigned getAssociatedConformanceIndex(
412-
const ProtocolConformance *conformance,
432+
// list of the requirement signature of the protocol.
433+
static unsigned getAssociatedConformanceIndex(const ProtocolDecl *proto,
413434
CanType associatedType,
414435
ProtocolDecl *requirement) {
415436
unsigned index = 0;
416-
for (const auto &reqt :
417-
conformance->getProtocol()->getRequirementSignature()) {
437+
for (const auto &reqt : proto->getRequirementSignature()) {
418438
if (reqt.getKind() == RequirementKind::Conformance &&
419439
reqt.getFirstType()->getCanonicalType() == associatedType &&
420440
reqt.getSecondType()->castTo<ProtocolType>()->getDecl() ==
@@ -426,15 +446,31 @@ class LinkEntity {
426446
llvm_unreachable("requirement not found in protocol");
427447
}
428448

449+
// We store associated conformances using their index in the requirement
450+
// list of the requirement signature of the conformance's protocol.
451+
static unsigned getAssociatedConformanceIndex(
452+
const ProtocolConformance *conformance,
453+
CanType associatedType,
454+
ProtocolDecl *requirement) {
455+
return getAssociatedConformanceIndex(conformance->getProtocol(),
456+
associatedType, requirement);
457+
}
458+
429459
static std::pair<CanType, ProtocolDecl*>
430-
getAssociatedConformanceByIndex(const ProtocolConformance *conformance,
460+
getAssociatedConformanceByIndex(const ProtocolDecl *proto,
431461
unsigned index) {
432-
auto &reqt = conformance->getProtocol()->getRequirementSignature()[index];
462+
auto &reqt = proto->getRequirementSignature()[index];
433463
assert(reqt.getKind() == RequirementKind::Conformance);
434464
return { reqt.getFirstType()->getCanonicalType(),
435465
reqt.getSecondType()->castTo<ProtocolType>()->getDecl() };
436466
}
437467

468+
static std::pair<CanType, ProtocolDecl*>
469+
getAssociatedConformanceByIndex(const ProtocolConformance *conformance,
470+
unsigned index) {
471+
return getAssociatedConformanceByIndex(conformance->getProtocol(), index);
472+
}
473+
438474
void setForType(Kind kind, CanType type) {
439475
assert(isTypeKind(kind));
440476
Pointer = type.getPointer();
@@ -758,6 +794,18 @@ class LinkEntity {
758794
return entity;
759795
}
760796

797+
static LinkEntity
798+
forAssociatedConformanceDescriptor(ProtocolDecl *proto,
799+
CanType associatedType,
800+
ProtocolDecl *associatedProtocol) {
801+
LinkEntity entity;
802+
entity.setForProtocolAndAssociatedConformance(
803+
Kind::AssociatedConformanceDescriptor,
804+
proto, associatedType,
805+
associatedProtocol);
806+
return entity;
807+
}
808+
761809
static LinkEntity
762810
forAssociatedTypeMetadataAccessFunction(const ProtocolConformance *C,
763811
AssociatedType association) {
@@ -872,9 +920,15 @@ class LinkEntity {
872920
}
873921

874922
std::pair<CanType, ProtocolDecl *> getAssociatedConformance() const {
875-
assert(getKind() == Kind::AssociatedTypeWitnessTableAccessFunction);
876-
return getAssociatedConformanceByIndex(getProtocolConformance(),
923+
if (getKind() == Kind::AssociatedTypeWitnessTableAccessFunction) {
924+
return getAssociatedConformanceByIndex(getProtocolConformance(),
877925
LINKENTITY_GET_FIELD(Data, AssociatedConformanceIndex));
926+
}
927+
928+
assert(getKind() == Kind::AssociatedConformanceDescriptor);
929+
return getAssociatedConformanceByIndex(
930+
cast<ProtocolDecl>(getDecl()),
931+
LINKENTITY_GET_FIELD(Data, AssociatedConformanceIndex));
878932
}
879933

880934
ProtocolDecl *getAssociatedProtocol() const {

lib/Demangling/Demangler.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1827,6 +1827,14 @@ NodePointer Demangler::demangleThunkOrSpecialization() {
18271827
return createWithChild(Node::Kind::DefaultAssociatedTypeMetadataAccessor,
18281828
popAssocTypeName());
18291829

1830+
case 'n': {
1831+
NodePointer requirementTy = popProtocol();
1832+
auto assocTypePath = popAssocTypePath();
1833+
NodePointer protoTy = popNode(Node::Kind::Type);
1834+
return createWithChildren(Node::Kind::AssociatedConformanceDescriptor,
1835+
protoTy, assocTypePath, requirementTy);
1836+
}
1837+
18301838
case 'H':
18311839
case 'h': {
18321840
auto nodeKind = c == 'H' ? Node::Kind::KeyPathEqualsThunkHelper

lib/Demangling/NodePrinter.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ class NodePrinter {
308308
case Node::Kind::ProtocolListWithClass:
309309
case Node::Kind::Allocator:
310310
case Node::Kind::ArgumentTuple:
311+
case Node::Kind::AssociatedConformanceDescriptor:
311312
case Node::Kind::AssociatedTypeDescriptor:
312313
case Node::Kind::AssociatedTypeMetadataAccessor:
313314
case Node::Kind::AssociatedTypeWitnessTableAccessor:
@@ -1555,6 +1556,14 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
15551556
Printer << "lazy cache variable for type metadata for ";
15561557
print(Node->getChild(0));
15571558
return nullptr;
1559+
case Node::Kind::AssociatedConformanceDescriptor:
1560+
Printer << "associated conformance descriptor for ";
1561+
print(Node->getChild(0));
1562+
Printer << ".";
1563+
print(Node->getChild(1));
1564+
Printer << ": ";
1565+
print(Node->getChild(2));
1566+
return nullptr;
15581567
case Node::Kind::AssociatedTypeDescriptor:
15591568
Printer << "associated type descriptor for ";
15601569
print(Node->getChild(0));

lib/Demangling/OldRemangler.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,10 @@ void Remangler::mangleAssociatedTypeDescriptor(Node *node) {
884884
Out << "<associated-type-descriptor>";
885885
}
886886

887+
void Remangler::mangleAssociatedConformanceDescriptor(Node *node) {
888+
Out << "<associated-conformance-descriptor>";
889+
}
890+
887891
void Remangler::mangleAssociatedTypeMetadataAccessor(Node *node) {
888892
Out << "Wt";
889893
mangleChildNodes(node); // protocol conformance, identifier

lib/Demangling/Remangler.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,11 @@ void Remangler::mangleAssociatedTypeDescriptor(Node *node) {
574574
Buffer << "Tl";
575575
}
576576

577+
void Remangler::mangleAssociatedConformanceDescriptor(Node *node) {
578+
mangleChildNodes(node);
579+
Buffer << "Tn";
580+
}
581+
577582
void Remangler::mangleAssociatedTypeMetadataAccessor(Node *node) {
578583
mangleChildNodes(node); // protocol conformance, identifier
579584
Buffer << "Wt";

lib/IRGen/GenDecl.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3387,6 +3387,16 @@ llvm::GlobalValue *IRGenModule::defineAssociatedTypeDescriptor(
33873387
return defineAlias(entity, definition);
33883388
}
33893389

3390+
llvm::GlobalValue *IRGenModule::defineAssociatedConformanceDescriptor(
3391+
ProtocolDecl *proto,
3392+
CanType subject,
3393+
ProtocolDecl *requirement,
3394+
llvm::Constant *definition) {
3395+
auto entity = LinkEntity::forAssociatedConformanceDescriptor(proto, subject,
3396+
requirement);
3397+
return defineAlias(entity, definition);
3398+
}
3399+
33903400
llvm::Constant *IRGenModule::getAddrOfProtocolConformanceDescriptor(
33913401
const NormalProtocolConformance *conformance,
33923402
ConstantInit definition) {

lib/IRGen/GenMeta.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,16 @@ namespace {
709709
B.getAddrOfCurrentPosition(IGM.ProtocolRequirementStructTy));
710710
}
711711

712+
if (entry.isAssociatedConformance()) {
713+
// Define the associated conformance descriptor to point to the
714+
// current position in the protocol descriptor.
715+
IGM.defineAssociatedConformanceDescriptor(
716+
Proto,
717+
entry.getAssociatedConformancePath(),
718+
entry.getAssociatedConformanceRequirement(),
719+
B.getAddrOfCurrentPosition(IGM.ProtocolRequirementStructTy));
720+
}
721+
712722
auto reqt = B.beginStruct(IGM.ProtocolRequirementStructTy);
713723

714724
auto info = getRequirementInfo(entry);

lib/IRGen/IRGenMangler.h

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,19 @@ class IRGenMangler : public Mangle::ASTMangler {
184184
return finalize();
185185
}
186186

187+
std::string mangleAssociatedConformanceDescriptor(
188+
const ProtocolDecl *proto,
189+
CanType subject,
190+
const ProtocolDecl *requirement) {
191+
beginMangling();
192+
appendAnyGenericType(proto);
193+
bool isFirstAssociatedTypeIdentifier = true;
194+
appendAssociatedTypePath(subject, isFirstAssociatedTypeIdentifier);
195+
appendProtocolName(requirement);
196+
appendOperator("Tn");
197+
return finalize();
198+
}
199+
187200
std::string mangleProtocolConformanceDescriptor(
188201
const ProtocolConformance *Conformance) {
189202
beginMangling();
@@ -413,13 +426,6 @@ class IRGenMangler : public Mangle::ASTMangler {
413426

414427
std::string manglePartialApplyForwarder(StringRef FuncName);
415428

416-
std::string mangleForProtocolDescriptor(ProtocolType *Proto) {
417-
beginMangling();
418-
appendProtocolName(Proto->getDecl(), /*allowStandardSubstitution=*/false);
419-
appendOperator("P");
420-
return finalize();
421-
}
422-
423429
std::string mangleTypeForForeignMetadataUniquing(Type type) {
424430
return mangleTypeWithoutPrefix(type);
425431
}

lib/IRGen/IRGenModule.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,6 +1234,11 @@ private: \
12341234
llvm::GlobalValue *defineAssociatedTypeDescriptor(
12351235
AssociatedTypeDecl *assocType,
12361236
llvm::Constant *definition);
1237+
llvm::GlobalValue *defineAssociatedConformanceDescriptor(
1238+
ProtocolDecl *proto,
1239+
CanType subject,
1240+
ProtocolDecl *requirement,
1241+
llvm::Constant *definition);
12371242

12381243
llvm::Constant *getAddrOfProtocolDescriptor(ProtocolDecl *D,
12391244
ConstantInit definition = ConstantInit());

lib/IRGen/Linking.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,14 @@ std::string LinkEntity::mangleAsString() const {
179179
return mangler.mangleAssociatedTypeDescriptor(
180180
cast<AssociatedTypeDecl>(getDecl()));
181181

182+
case Kind::AssociatedConformanceDescriptor: {
183+
auto assocConformance = getAssociatedConformance();
184+
return mangler.mangleAssociatedConformanceDescriptor(
185+
cast<ProtocolDecl>(getDecl()),
186+
assocConformance.first,
187+
assocConformance.second);
188+
}
189+
182190
case Kind::ProtocolConformanceDescriptor:
183191
return mangler.mangleProtocolConformanceDescriptor(
184192
cast<NormalProtocolConformance>(getProtocolConformance()));
@@ -449,6 +457,7 @@ SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const {
449457
return getSILLinkage(getDeclLinkage(getterDecl), forDefinition);
450458
}
451459

460+
case Kind::AssociatedConformanceDescriptor:
452461
case Kind::ObjCClass:
453462
case Kind::ObjCMetaclass:
454463
case Kind::SwiftMetaclassStub:
@@ -586,6 +595,7 @@ bool LinkEntity::isAvailableExternally(IRGenModule &IGM) const {
586595
// FIXME: Removing this triggers a linker bug
587596
return true;
588597

598+
case Kind::AssociatedConformanceDescriptor:
589599
case Kind::SwiftMetaclassStub:
590600
case Kind::ClassMetadataBaseOffset:
591601
case Kind::PropertyDescriptor:

lib/TBDGen/TBDGen.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,15 @@ void TBDGenVisitor::addAssociatedTypeDescriptor(AssociatedTypeDecl *assocType) {
9999
addSymbol(entity);
100100
}
101101

102+
void TBDGenVisitor::addAssociatedConformanceDescriptor(
103+
ProtocolDecl *proto,
104+
CanType subject,
105+
ProtocolDecl *requirement) {
106+
auto entity = LinkEntity::forAssociatedConformanceDescriptor(proto, subject,
107+
requirement);
108+
addSymbol(entity);
109+
}
110+
102111
void TBDGenVisitor::addConformances(DeclContext *DC) {
103112
for (auto conformance : DC->getLocalConformances()) {
104113
auto protocol = conformance->getProtocol();
@@ -409,6 +418,20 @@ void TBDGenVisitor::visitProtocolDecl(ProtocolDecl *PD) {
409418
if (protocolDescriptorHasRequirements(PD))
410419
addProtocolRequirementsBaseDescriptor(PD);
411420

421+
for (const auto &req : PD->getRequirementSignature()) {
422+
if (req.getKind() != RequirementKind::Conformance)
423+
continue;
424+
425+
// Skip inherited requirements.
426+
if (req.getFirstType()->isEqual(PD->getProtocolSelfType()))
427+
continue;
428+
429+
addAssociatedConformanceDescriptor(
430+
PD,
431+
req.getFirstType()->getCanonicalType(),
432+
req.getSecondType()->castTo<ProtocolType>()->getDecl());
433+
}
434+
412435
for (auto *member : PD->getMembers()) {
413436
if (PD->isResilient()) {
414437
if (auto *funcDecl = dyn_cast<AbstractFunctionDecl>(member)) {

lib/TBDGen/TBDGenVisitor.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ class TBDGenVisitor : public ASTVisitor<TBDGenVisitor> {
6666

6767
void addProtocolRequirementsBaseDescriptor(ProtocolDecl *proto);
6868
void addAssociatedTypeDescriptor(AssociatedTypeDecl *assocType);
69+
void addAssociatedConformanceDescriptor(ProtocolDecl *proto,
70+
CanType subject,
71+
ProtocolDecl *requirement);
6972

7073
public:
7174
TBDGenVisitor(tapi::internal::InterfaceFile &symbols,

test/Demangle/Inputs/manglings.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,3 +331,4 @@ $S2t21QP22ProtocolTypeAliasThingayAA4BlahV5SomeQa_GSgD ---> t2.Blah.SomeQ as t2.
331331
A.h<A>(A) -> ()inlined generic function <(A, A1)> of
332332
$S1T19protocol_resilience17ResilientProtocolPTl --> associated type descriptor for T
333333
$S18resilient_protocol21ResilientBaseProtocolTL --> protocol requirements base descriptor for resilient_protocol.ResilientBaseProtocol
334+
$S1t1PP10AssocType2_AA1QTn --> associated conformance descriptor for t.P.AssocType2: t.Q

test/IRGen/protocol_resilience_descriptors.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,16 @@
2020
// Protocol requirements base descriptor
2121
// CHECK-DEFINITION: @"$S18resilient_protocol21ResilientBaseProtocolTL" ={{( dllexport)?}}{{( protected)?}} alias %swift.protocol_requirement, getelementptr (%swift.protocol_requirement, %swift.protocol_requirement* getelementptr inbounds (<{ i32, i32, i32, i32, i32, i32, %swift.protocol_requirement }>, <{ i32, i32, i32, i32, i32, i32, %swift.protocol_requirement }>* @"$S18resilient_protocol21ResilientBaseProtocolMp", i32 0, i32 6), i32 -1)
2222

23-
// Associated type requirement aliases
23+
// Associated type and conformance
2424

2525
// CHECK-DEFINITION: @"$S1T18resilient_protocol24ProtocolWithRequirementsPTl" ={{( dllexport)?}}{{( protected)?}} alias
26+
// CHECK-DEFINITION: @"$S18resilient_protocol29ProtocolWithAssocTypeDefaultsP2T2_AA014OtherResilientC0Tn" ={{( dllexport)?}}{{( protected)?}} alias
2627

2728
// Default associated type witnesses
2829
// CHECK-DEFINITION-LABEL: define internal swiftcc %swift.metadata_response @"$S2T118resilient_protocol29ProtocolWithAssocTypeDefaultsPTM"
2930

3031
// CHECK-DEFINITION-LABEL: define internal swiftcc %swift.metadata_response @"$S2T218resilient_protocol29ProtocolWithAssocTypeDefaultsPTM"
31-
// CHECK-DEFINITION: getelementptr inbounds i8*, i8** [[WTABLE:%.*]], i32 1
32+
// CHECK-DEFINITION: getelementptr inbounds i8*, i8** [[WTABLE:%.*]], i32 2
3233
// CHECK-DEFINITION: call{{.*}}S18resilient_protocol7WrapperVMa
3334

3435
import resilient_protocol

test/Inputs/resilient_protocol.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ public protocol ProtocolWithRequirements {
2828
func second()
2929
}
3030

31-
public struct Wrapper<T> { }
31+
public struct Wrapper<T>: OtherResilientProtocol { }
3232

3333
public protocol ProtocolWithAssocTypeDefaults {
3434
associatedtype T1 = Self
35-
associatedtype T2 = Wrapper<T1>
35+
associatedtype T2: OtherResilientProtocol = Wrapper<T1>
3636
}

0 commit comments

Comments
 (0)