Skip to content

Commit d076e41

Browse files
committed
[IRGen] Put associated conformance accessors in resilient witness table
For a resilient conformance, emit the associated conformance accessor functions into the resilient witness table (keyed on the associated conformance descriptor) rather than in the fixed part of the witness table. This is another part of resilience for associated conformances, and a step toward defaults for associated conformances.
1 parent 241bcdf commit d076e41

File tree

9 files changed

+90
-48
lines changed

9 files changed

+90
-48
lines changed

include/swift/IRGen/Linking.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -795,14 +795,13 @@ class LinkEntity {
795795
}
796796

797797
static LinkEntity
798-
forAssociatedConformanceDescriptor(ProtocolDecl *proto,
799-
CanType associatedType,
800-
ProtocolDecl *associatedProtocol) {
798+
forAssociatedConformanceDescriptor(AssociatedConformance conformance) {
801799
LinkEntity entity;
802800
entity.setForProtocolAndAssociatedConformance(
803801
Kind::AssociatedConformanceDescriptor,
804-
proto, associatedType,
805-
associatedProtocol);
802+
conformance.getSourceProtocol(),
803+
conformance.getAssociation(),
804+
conformance.getAssociatedRequirement());
806805
return entity;
807806
}
808807

lib/IRGen/GenDecl.cpp

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3389,21 +3389,15 @@ llvm::GlobalValue *IRGenModule::defineAssociatedTypeDescriptor(
33893389

33903390
llvm::Constant *IRGenModule::getAddrOfAssociatedConformanceDescriptor(
33913391
AssociatedConformance conformance) {
3392-
auto entity = LinkEntity::forAssociatedConformanceDescriptor(
3393-
conformance.getSourceProtocol(),
3394-
conformance.getAssociation(),
3395-
conformance.getAssociatedRequirement());
3392+
auto entity = LinkEntity::forAssociatedConformanceDescriptor(conformance);
33963393
return getAddrOfLLVMVariable(entity, getPointerAlignment(), ConstantInit(),
33973394
ProtocolRequirementStructTy, DebugTypeInfo());
33983395
}
33993396

34003397
llvm::GlobalValue *IRGenModule::defineAssociatedConformanceDescriptor(
3401-
ProtocolDecl *proto,
3402-
CanType subject,
3403-
ProtocolDecl *requirement,
3404-
llvm::Constant *definition) {
3405-
auto entity = LinkEntity::forAssociatedConformanceDescriptor(proto, subject,
3406-
requirement);
3398+
AssociatedConformance conformance,
3399+
llvm::Constant *definition) {
3400+
auto entity = LinkEntity::forAssociatedConformanceDescriptor(conformance);
34073401
return defineAlias(entity, definition);
34083402
}
34093403

lib/IRGen/GenMeta.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -712,10 +712,12 @@ namespace {
712712
if (entry.isAssociatedConformance()) {
713713
// Define the associated conformance descriptor to point to the
714714
// current position in the protocol descriptor.
715+
AssociatedConformance conformance(
716+
Proto,
717+
entry.getAssociatedConformancePath(),
718+
entry.getAssociatedConformanceRequirement());
715719
IGM.defineAssociatedConformanceDescriptor(
716-
Proto,
717-
entry.getAssociatedConformancePath(),
718-
entry.getAssociatedConformanceRequirement(),
720+
conformance,
719721
B.getAddrOfCurrentPosition(IGM.ProtocolRequirementStructTy));
720722
}
721723

lib/IRGen/GenProto.cpp

Lines changed: 60 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,6 +1385,13 @@ llvm::Value *uniqueForeignWitnessTableRef(IRGenFunction &IGF,
13851385
void addAssociatedConformance(AssociatedConformance requirement) {
13861386
// FIXME: Add static witness tables for type conformances.
13871387

1388+
auto &entry = SILEntries.front();
1389+
(void)entry;
1390+
SILEntries = SILEntries.slice(1);
1391+
1392+
if (ResilientConformance)
1393+
return;
1394+
13881395
auto associate =
13891396
ConformanceInContext.getAssociatedType(
13901397
requirement.getAssociation())->getCanonicalType();
@@ -1394,9 +1401,8 @@ llvm::Value *uniqueForeignWitnessTableRef(IRGenFunction &IGF,
13941401
requirement.getAssociation(),
13951402
requirement.getAssociatedRequirement());
13961403

1404+
13971405
#ifndef NDEBUG
1398-
auto &entry = SILEntries.front();
1399-
(void)entry;
14001406
assert(entry.getKind() == SILWitnessTable::AssociatedTypeProtocol
14011407
&& "sil witness table does not match protocol");
14021408
auto associatedWitness = entry.getAssociatedTypeProtocolWitness();
@@ -1411,8 +1417,6 @@ llvm::Value *uniqueForeignWitnessTableRef(IRGenFunction &IGF,
14111417
"offset doesn't match ProtocolInfo layout");
14121418
#endif
14131419

1414-
SILEntries = SILEntries.slice(1);
1415-
14161420
llvm::Constant *wtableAccessFunction =
14171421
getAssociatedTypeWitnessTableAccessFunction(requirement,
14181422
associate,
@@ -1644,7 +1648,8 @@ llvm::Constant *WitnessTableBuilder::
16441648
getAssociatedTypeWitnessTableAccessFunction(AssociatedConformance requirement,
16451649
CanType associatedType,
16461650
ProtocolConformanceRef associatedConformance) {
1647-
if (!associatedType->hasArchetype()) {
1651+
bool hasArchetype = associatedType->hasArchetype();
1652+
if (!hasArchetype && !ResilientConformance) {
16481653
assert(associatedConformance.isConcrete() &&
16491654
"no concrete conformance for non-dependent type");
16501655
return getOrCreateWitnessTableAccessFunction(IGM,
@@ -1682,13 +1687,6 @@ getAssociatedTypeWitnessTableAccessFunction(AssociatedConformance requirement,
16821687
Address destTable(parameters.claimNext(), IGM.getPointerAlignment());
16831688
setProtocolWitnessTableName(IGM, destTable.getAddress(), ConcreteType,
16841689
Conformance.getProtocol());
1685-
IGF.bindLocalTypeDataFromSelfWitnessTable(
1686-
&Conformance,
1687-
destTable.getAddress(),
1688-
[&](CanType type) {
1689-
return Conformance.getDeclContext()->mapTypeIntoContext(type)
1690-
->getCanonicalType();
1691-
});
16921690

16931691
ProtocolDecl *associatedProtocol = requirement.getAssociatedRequirement();
16941692

@@ -1710,6 +1708,24 @@ getAssociatedTypeWitnessTableAccessFunction(AssociatedConformance requirement,
17101708
}
17111709
}
17121710

1711+
// If there are no archetypes, return a reference to the table. There is
1712+
// no need for a cache.
1713+
if (!hasArchetype) {
1714+
auto wtable = MetadataResponse::forComplete(
1715+
conformanceI->getTable(IGF, &associatedTypeMetadata))
1716+
.getMetadata();
1717+
IGF.Builder.CreateRet(wtable);
1718+
return accessor;
1719+
}
1720+
1721+
IGF.bindLocalTypeDataFromSelfWitnessTable(
1722+
&Conformance,
1723+
destTable.getAddress(),
1724+
[&](CanType type) {
1725+
return Conformance.getDeclContext()->mapTypeIntoContext(type)
1726+
->getCanonicalType();
1727+
});
1728+
17131729
// If the witness table is directly fulfillable from the type,
17141730
// we don't need a cache entry.
17151731
// TODO: maybe we should have a cache entry anyway if the fulfillment
@@ -1869,7 +1885,8 @@ llvm::Constant *WitnessTableBuilder::emitResilientWitnessTable() {
18691885
unsigned count = 0;
18701886
for (auto &entry : SILWT->getEntries()) {
18711887
if (entry.getKind() != SILWitnessTable::Method &&
1872-
entry.getKind() != SILWitnessTable::AssociatedType)
1888+
entry.getKind() != SILWitnessTable::AssociatedType &&
1889+
entry.getKind() != SILWitnessTable::AssociatedTypeProtocol)
18731890
continue;
18741891

18751892
count++;
@@ -1907,6 +1924,36 @@ llvm::Constant *WitnessTableBuilder::emitResilientWitnessTable() {
19071924
continue;
19081925
}
19091926

1927+
// Associated conformance access function.
1928+
if (entry.getKind() == SILWitnessTable::AssociatedTypeProtocol) {
1929+
const auto &witness = entry.getAssociatedTypeProtocolWitness();
1930+
1931+
// Associated type descriptor.
1932+
AssociatedConformance requirement(SILWT->getConformance()->getProtocol(),
1933+
witness.Requirement,
1934+
witness.Protocol);
1935+
auto assocConformanceDescriptor =
1936+
IGM.getAddrOfLLVMVariableOrGOTEquivalent(
1937+
LinkEntity::forAssociatedConformanceDescriptor(requirement),
1938+
Alignment(4), IGM.ProtocolRequirementStructTy);
1939+
table.addRelativeAddress(assocConformanceDescriptor);
1940+
1941+
auto associate =
1942+
ConformanceInContext.getAssociatedType(
1943+
witness.Requirement)->getCanonicalType();
1944+
1945+
ProtocolConformanceRef associatedConformance =
1946+
ConformanceInContext.getAssociatedConformance(witness.Requirement,
1947+
witness.Protocol);
1948+
1949+
llvm::Constant *wtableAccessFunction =
1950+
getAssociatedTypeWitnessTableAccessFunction(requirement,
1951+
associate,
1952+
associatedConformance);
1953+
table.addRelativeAddress(wtableAccessFunction);
1954+
continue;
1955+
}
1956+
19101957
if (entry.getKind() != SILWitnessTable::Method)
19111958
continue;
19121959

lib/IRGen/IRGenModule.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,10 +1237,8 @@ private: \
12371237
llvm::Constant *getAddrOfAssociatedConformanceDescriptor(
12381238
AssociatedConformance conformance);
12391239
llvm::GlobalValue *defineAssociatedConformanceDescriptor(
1240-
ProtocolDecl *proto,
1241-
CanType subject,
1242-
ProtocolDecl *requirement,
1243-
llvm::Constant *definition);
1240+
AssociatedConformance conformance,
1241+
llvm::Constant *definition);
12441242

12451243
llvm::Constant *getAddrOfProtocolDescriptor(ProtocolDecl *D,
12461244
ConstantInit definition = ConstantInit());

lib/TBDGen/TBDGen.cpp

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,8 @@ void TBDGenVisitor::addAssociatedTypeDescriptor(AssociatedTypeDecl *assocType) {
100100
}
101101

102102
void TBDGenVisitor::addAssociatedConformanceDescriptor(
103-
ProtocolDecl *proto,
104-
CanType subject,
105-
ProtocolDecl *requirement) {
106-
auto entity = LinkEntity::forAssociatedConformanceDescriptor(proto, subject,
107-
requirement);
103+
AssociatedConformance conformance) {
104+
auto entity = LinkEntity::forAssociatedConformanceDescriptor(conformance);
108105
addSymbol(entity);
109106
}
110107

@@ -426,10 +423,11 @@ void TBDGenVisitor::visitProtocolDecl(ProtocolDecl *PD) {
426423
if (req.getFirstType()->isEqual(PD->getProtocolSelfType()))
427424
continue;
428425

429-
addAssociatedConformanceDescriptor(
430-
PD,
431-
req.getFirstType()->getCanonicalType(),
432-
req.getSecondType()->castTo<ProtocolType>()->getDecl());
426+
AssociatedConformance conformance(
427+
PD,
428+
req.getFirstType()->getCanonicalType(),
429+
req.getSecondType()->castTo<ProtocolType>()->getDecl());
430+
addAssociatedConformanceDescriptor(conformance);
433431
}
434432

435433
for (auto *member : PD->getMembers()) {

lib/TBDGen/TBDGenVisitor.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,7 @@ 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);
69+
void addAssociatedConformanceDescriptor(AssociatedConformance conformance);
7270

7371
public:
7472
TBDGenVisitor(tapi::internal::InterfaceFile &symbols,

stdlib/public/runtime/Metadata.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3650,9 +3650,9 @@ static void initializeResilientWitnessTable(GenericWitnessTable *genericTable,
36503650
case ProtocolRequirementFlags::Kind::ReadCoroutine:
36513651
case ProtocolRequirementFlags::Kind::ModifyCoroutine:
36523652
case ProtocolRequirementFlags::Kind::AssociatedTypeAccessFunction:
3653+
case ProtocolRequirementFlags::Kind::AssociatedConformanceAccessFunction:
36533654
break;
36543655
case ProtocolRequirementFlags::Kind::BaseProtocol:
3655-
case ProtocolRequirementFlags::Kind::AssociatedConformanceAccessFunction:
36563656
continue;
36573657
}
36583658

test/IRGen/protocol_resilience_descriptors.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ public protocol P { }
5151
public struct ConditionallyConforms<Element> { }
5252
public struct Y { }
5353

54+
// CHECK-USAGE: @"$S31protocol_resilience_descriptors29ConformsWithAssocRequirementsV010resilient_A008ProtocoleF12TypeDefaultsAAWr" = internal
55+
// CHECK-USAGE-SAME: $S18resilient_protocol29ProtocolWithAssocTypeDefaultsP2T2_AA014OtherResilientC0Tn
56+
// CHECK-USAGE-SAME: $S31protocol_resilience_descriptors29ConformsWithAssocRequirementsV010resilient_A008ProtocoleF12TypeDefaultsAA2T2_AD014OtherResilientI0PWT
57+
public struct ConformsWithAssocRequirements : ProtocolWithAssocTypeDefaults {
58+
}
59+
5460
// CHECK-USAGE: @"$Sx1T_MXA" =
5561
// CHECK-USAGE-SAME: i32 0
5662
// CHECK-USAGE-SAME: @"{{got.|__imp_}}$S18resilient_protocol24ProtocolWithRequirementsMp"

0 commit comments

Comments
 (0)