Skip to content

Commit 0a0a3c6

Browse files
authored
Merge pull request #15573 from slavapestov/dependent-conformance-records
Fix dependent protocol conformance records
2 parents 8695224 + 30a3e75 commit 0a0a3c6

19 files changed

+135
-56
lines changed

include/swift/Demangling/DemangleNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ NODE(ProtocolListWithAnyObject)
145145
NODE(ProtocolWitness)
146146
NODE(ProtocolWitnessTable)
147147
NODE(ProtocolWitnessTableAccessor)
148+
NODE(ProtocolWitnessTablePattern)
148149
NODE(QualifiedArchetype)
149150
NODE(ReabstractionThunk)
150151
NODE(ReabstractionThunkHelper)

include/swift/IRGen/Linking.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,10 @@ class LinkEntity {
199199
/// ProtocolConformance*.
200200
DirectProtocolWitnessTable,
201201

202+
/// A protocol witness table pattern. The secondary pointer is a
203+
/// ProtocolConformance*.
204+
ProtocolWitnessTablePattern,
205+
202206
/// A witness accessor function. The secondary pointer is a
203207
/// ProtocolConformance*.
204208
ProtocolWitnessTableAccessFunction,
@@ -615,6 +619,13 @@ class LinkEntity {
615619
return entity;
616620
}
617621

622+
static LinkEntity
623+
forProtocolWitnessTablePattern(const ProtocolConformance *C) {
624+
LinkEntity entity;
625+
entity.setForProtocolConformance(Kind::ProtocolWitnessTablePattern, C);
626+
return entity;
627+
}
628+
618629
static LinkEntity
619630
forProtocolWitnessTableAccessFunction(const ProtocolConformance *C) {
620631
LinkEntity entity;

lib/Demangling/Demangler.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2072,6 +2072,9 @@ NodePointer Demangler::demangleWitness() {
20722072
case 'P':
20732073
return createWithChild(Node::Kind::ProtocolWitnessTable,
20742074
popProtocolConformance());
2075+
case 'p':
2076+
return createWithChild(Node::Kind::ProtocolWitnessTablePattern,
2077+
popProtocolConformance());
20752078
case 'G':
20762079
return createWithChild(Node::Kind::GenericProtocolWitnessTable,
20772080
popProtocolConformance());

lib/Demangling/NodePrinter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ class NodePrinter {
403403
case Node::Kind::ProtocolWitness:
404404
case Node::Kind::ProtocolWitnessTable:
405405
case Node::Kind::ProtocolWitnessTableAccessor:
406+
case Node::Kind::ProtocolWitnessTablePattern:
406407
case Node::Kind::ReabstractionThunk:
407408
case Node::Kind::ReabstractionThunkHelper:
408409
case Node::Kind::RelatedEntityDeclName:
@@ -1303,6 +1304,10 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
13031304
Printer << "protocol witness table for ";
13041305
print(Node->getFirstChild());
13051306
return nullptr;
1307+
case Node::Kind::ProtocolWitnessTablePattern:
1308+
Printer << "protocol witness table pattern for ";
1309+
print(Node->getFirstChild());
1310+
return nullptr;
13061311
case Node::Kind::GenericProtocolWitnessTable:
13071312
Printer << "generic protocol witness table for ";
13081313
print(Node->getFirstChild());

lib/Demangling/OldRemangler.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,10 @@ void Remangler::mangleProtocolRequirementArray(Node *node) {
760760
unreachable("todo");
761761
}
762762

763+
void Remangler::mangleProtocolWitnessTablePattern(Node *node) {
764+
unreachable("todo");
765+
}
766+
763767
void Remangler::mangleProtocolConformanceDescriptor(Node *node) {
764768
Out << "Mc";
765769
mangleProtocolConformance(node->begin()[0]);

lib/Demangling/Remangler.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1562,6 +1562,11 @@ void Remangler::mangleProtocolWitnessTable(Node *node) {
15621562
Buffer << "WP";
15631563
}
15641564

1565+
void Remangler::mangleProtocolWitnessTablePattern(Node *node) {
1566+
mangleSingleChildNode(node);
1567+
Buffer << "Wp";
1568+
}
1569+
15651570
void Remangler::mangleProtocolWitnessTableAccessor(Node *node) {
15661571
mangleSingleChildNode(node);
15671572
Buffer << "Wa";

lib/IRGen/GenDecl.cpp

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
#include "GenMeta.h"
6060
#include "GenObjC.h"
6161
#include "GenOpaque.h"
62+
#include "GenProto.h"
6263
#include "GenType.h"
6364
#include "IRGenDebugInfo.h"
6465
#include "IRGenFunction.h"
@@ -1566,6 +1567,11 @@ SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const {
15661567
case Kind::ProtocolConformanceDescriptor:
15671568
return getLinkageAsConformance();
15681569

1570+
case Kind::ProtocolWitnessTablePattern:
1571+
if (getLinkageAsConformance() == SILLinkage::Shared)
1572+
return SILLinkage::Shared;
1573+
return SILLinkage::Private;
1574+
15691575
case Kind::ProtocolWitnessTableLazyAccessFunction:
15701576
case Kind::ProtocolWitnessTableLazyCacheVariable: {
15711577
auto *nominal = getType().getAnyNominal();
@@ -1662,7 +1668,6 @@ bool LinkEntity::isAvailableExternally(IRGenModule &IGM) const {
16621668
case Kind::PropertyDescriptor:
16631669
case Kind::NominalTypeDescriptor:
16641670
case Kind::ProtocolDescriptor:
1665-
case Kind::ProtocolRequirementArray:
16661671
return ::isAvailableExternally(IGM, getDecl());
16671672

16681673
case Kind::EnumCase:
@@ -1672,6 +1677,8 @@ bool LinkEntity::isAvailableExternally(IRGenModule &IGM) const {
16721677
case Kind::ProtocolConformanceDescriptor:
16731678
return ::isAvailableExternally(IGM, getProtocolConformance()->getDeclContext());
16741679

1680+
case Kind::ProtocolWitnessTablePattern:
1681+
case Kind::ProtocolRequirementArray:
16751682
case Kind::ObjCClassRef:
16761683
case Kind::ModuleDescriptor:
16771684
case Kind::ExtensionDescriptor:
@@ -2730,31 +2737,29 @@ namespace {
27302737
void addWitnessTable() {
27312738
using ConformanceKind = ConformanceFlags::ConformanceKind;
27322739

2733-
// Figure out what kind of witness table we have.
2734-
auto proto = Conformance->getProtocol();
2740+
// Figure out what kind of witness table we have.
27352741
llvm::Constant *witnessTableVar;
2736-
if (!IGM.isResilient(proto, ResilienceExpansion::Maximal) &&
2737-
Conformance->getConditionalRequirements().empty()) {
2738-
Flags = Flags.withConformanceKind(ConformanceKind::WitnessTable);
2739-
2740-
// If the conformance is in this object's table, then the witness table
2741-
// should also be in this object file, so we can always directly
2742-
// reference it.
2743-
witnessTableVar = IGM.getAddrOfWitnessTable(Conformance);
2744-
} else {
2745-
if (Conformance->getConditionalRequirements().empty()) {
2742+
2743+
if (Conformance->getConditionalRequirements().empty()) {
2744+
if (!isDependentConformance(IGM, Conformance,
2745+
ResilienceExpansion::Maximal)) {
2746+
Flags = Flags.withConformanceKind(ConformanceKind::WitnessTable);
2747+
witnessTableVar = IGM.getAddrOfWitnessTable(Conformance);
2748+
} else {
27462749
Flags = Flags.withConformanceKind(
27472750
ConformanceKind::WitnessTableAccessor);
2748-
} else {
2749-
Flags =
2750-
Flags.withConformanceKind(
2751-
ConformanceKind::ConditionalWitnessTableAccessor)
2752-
.withNumConditionalRequirements(
2753-
Conformance->getConditionalRequirements().size());
2751+
witnessTableVar = IGM.getAddrOfWitnessTableAccessFunction(
2752+
Conformance, ForDefinition);
27542753
}
2754+
} else {
2755+
Flags =
2756+
Flags.withConformanceKind(
2757+
ConformanceKind::ConditionalWitnessTableAccessor)
2758+
.withNumConditionalRequirements(
2759+
Conformance->getConditionalRequirements().size());
27552760

27562761
witnessTableVar = IGM.getAddrOfWitnessTableAccessFunction(
2757-
Conformance, ForDefinition);
2762+
Conformance, ForDefinition);
27582763
}
27592764

27602765
// Relative reference to the witness table.
@@ -4126,10 +4131,7 @@ IRGenModule::getAddrOfWitnessTableLazyCacheVariable(
41264131

41274132
/// Look up the address of a witness table.
41284133
///
4129-
/// TODO: This needs to take a flag for the access mode of the witness table,
4130-
/// which may be direct, lazy, or a runtime instantiation template.
4131-
/// TODO: Use name from witness table here to lookup witness table instead of
4132-
/// recomputing it.
4134+
/// This can only be used with non-dependent conformances.
41334135
llvm::Constant*
41344136
IRGenModule::getAddrOfWitnessTable(const NormalProtocolConformance *conf,
41354137
ConstantInit definition) {
@@ -4140,6 +4142,20 @@ IRGenModule::getAddrOfWitnessTable(const NormalProtocolConformance *conf,
41404142
WitnessTableTy, DebugTypeInfo());
41414143
}
41424144

4145+
/// Look up the address of a witness table pattern.
4146+
///
4147+
/// This can only be used with dependent conformances from inside the
4148+
/// defining module.
4149+
llvm::Constant*
4150+
IRGenModule::getAddrOfWitnessTablePattern(const NormalProtocolConformance *conf,
4151+
ConstantInit definition) {
4152+
IRGen.addLazyWitnessTable(conf);
4153+
4154+
auto entity = LinkEntity::forProtocolWitnessTablePattern(conf);
4155+
return getAddrOfLLVMVariable(entity, getPointerAlignment(), definition,
4156+
WitnessTableTy, DebugTypeInfo());
4157+
}
4158+
41434159
llvm::Function *
41444160
IRGenModule::getAddrOfAssociatedTypeMetadataAccessFunction(
41454161
const NormalProtocolConformance *conformance,

lib/IRGen/GenFunc.cpp

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,7 +1346,7 @@ void irgen::emitFunctionPartialApplication(
13461346
SmallVector<SILType, 4> argValTypes;
13471347
SmallVector<ParameterConvention, 4> argConventions;
13481348

1349-
bool isNoEscapeFunction = outType->isNoEscape();
1349+
assert(!outType->isNoEscape());
13501350

13511351
// Reserve space for polymorphic bindings.
13521352
SubstitutionMap subMap;
@@ -1476,10 +1476,7 @@ void irgen::emitFunctionPartialApplication(
14761476
fnPtr = IGF.Builder.CreateBitCast(fnPtr, IGF.IGM.Int8PtrTy);
14771477
out.add(fnPtr);
14781478
llvm::Value *ctx = args.claimNext();
1479-
if (isNoEscapeFunction)
1480-
ctx = IGF.Builder.CreateBitCast(ctx, IGF.IGM.OpaquePtrTy);
1481-
else
1482-
ctx = IGF.Builder.CreateBitCast(ctx, IGF.IGM.RefCountedPtrTy);
1479+
ctx = IGF.Builder.CreateBitCast(ctx, IGF.IGM.RefCountedPtrTy);
14831480
out.add(ctx);
14841481
return;
14851482
}
@@ -1520,10 +1517,7 @@ void irgen::emitFunctionPartialApplication(
15201517
llvm::Value *ctx = args.claimNext();
15211518
if (isIndirectFormalParameter(*singleRefcountedConvention))
15221519
ctx = IGF.Builder.CreateLoad(ctx, IGF.IGM.getPointerAlignment());
1523-
if (isNoEscapeFunction)
1524-
ctx = IGF.Builder.CreateBitCast(ctx, IGF.IGM.OpaquePtrTy);
1525-
else
1526-
ctx = IGF.Builder.CreateBitCast(ctx, IGF.IGM.RefCountedPtrTy);
1520+
ctx = IGF.Builder.CreateBitCast(ctx, IGF.IGM.RefCountedPtrTy);
15271521
out.add(ctx);
15281522
return;
15291523
}
@@ -1614,8 +1608,6 @@ void irgen::emitFunctionPartialApplication(
16141608
argConventions);
16151609
forwarder = IGF.Builder.CreateBitCast(forwarder, IGF.IGM.Int8PtrTy);
16161610
out.add(forwarder);
1617-
if (isNoEscapeFunction)
1618-
data = IGF.Builder.CreateBitCast(data, IGF.IGM.OpaquePtrTy);
16191611
out.add(data);
16201612
}
16211613

lib/IRGen/GenProto.cpp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -937,7 +937,7 @@ static bool isResilientConformance(const NormalProtocolConformance *conformance)
937937

938938
/// Is there anything about the given conformance that requires witness
939939
/// tables to be dependently-generated?
940-
static bool isDependentConformance(IRGenModule &IGM,
940+
bool irgen::isDependentConformance(IRGenModule &IGM,
941941
const NormalProtocolConformance *conformance,
942942
ResilienceExpansion expansion) {
943943
// If the conformance is resilient, this is always true.
@@ -946,6 +946,9 @@ static bool isDependentConformance(IRGenModule &IGM,
946946

947947
// Check whether any of the inherited conformances are dependent.
948948
for (auto inherited : conformance->getProtocol()->getInheritedProtocols()) {
949+
if (inherited->isObjC())
950+
continue;
951+
949952
if (isDependentConformance(IGM,
950953
conformance->getInheritedConformance(inherited)
951954
->getRootNormalConformance(),
@@ -2066,6 +2069,8 @@ void IRGenModule::emitSILWitnessTable(SILWitnessTable *wt) {
20662069
if (isAvailableExternally(wt->getLinkage()))
20672070
return;
20682071

2072+
auto *conf = wt->getConformance();
2073+
20692074
// Build the witnesses.
20702075
ConstantInitBuilder builder(*this);
20712076
auto wtableContents = builder.beginArray(Int8PtrTy);
@@ -2080,23 +2085,26 @@ void IRGenModule::emitSILWitnessTable(SILWitnessTable *wt) {
20802085
// Produce the initializer value.
20812086
auto initializer = wtableContents.finishAndCreateFuture();
20822087

2088+
bool isDependent = isDependentConformance(*this, conf,
2089+
ResilienceExpansion::Maximal);
20832090
auto global = cast<llvm::GlobalVariable>(
2084-
getAddrOfWitnessTable(wt->getConformance(), initializer));
2091+
isDependent
2092+
? getAddrOfWitnessTablePattern(conf, initializer)
2093+
: getAddrOfWitnessTable(conf, initializer));
20852094
global->setConstant(true);
20862095
global->setAlignment(getWitnessTableAlignment().getValue());
20872096

2088-
// FIXME: resilience; this should use the conformance's publishing scope.
2097+
// Always emit an accessor function.
20892098
wtableBuilder.buildAccessFunction(global);
20902099

20912100
// Behavior conformances can't be reflected.
2092-
if (wt->getConformance()->isBehaviorConformance())
2101+
if (conf->isBehaviorConformance())
20932102
return;
20942103

2095-
NormalProtocolConformance *Conf = wt->getConformance();
2096-
addProtocolConformance(Conf);
2104+
addProtocolConformance(conf);
20972105

20982106
// Trigger the lazy emission of the foreign type metadata.
2099-
CanType conformingType = Conf->getType()->getCanonicalType();
2107+
CanType conformingType = conf->getType()->getCanonicalType();
21002108
if (requiresForeignTypeMetadata(conformingType))
21012109
(void)getAddrOfForeignTypeMetadataCandidate(conformingType);
21022110
}

lib/IRGen/GenProto.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,10 @@ namespace irgen {
255255
CanSILFunctionType fnType,
256256
GenericParamFulfillmentCallback callback);
257257

258+
bool isDependentConformance(IRGenModule &IGM,
259+
const NormalProtocolConformance *conformance,
260+
ResilienceExpansion expansion);
261+
258262
} // end namespace irgen
259263
} // end namespace swift
260264

lib/IRGen/IRGenMangler.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,10 @@ class IRGenMangler : public Mangle::ASTMangler {
161161
return mangleConformanceSymbol(Type(), C, "WP");
162162
}
163163

164+
std::string mangleProtocolWitnessTablePattern(const ProtocolConformance *C) {
165+
return mangleConformanceSymbol(Type(), C, "Wp");
166+
}
167+
164168
std::string mangleGenericProtocolWitnessTableCache(
165169
const ProtocolConformance *C) {
166170
return mangleConformanceSymbol(Type(), C, "WG");

lib/IRGen/IRGenModule.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1201,7 +1201,10 @@ private: \
12011201
CanType conformingType,
12021202
ForDefinition_t forDefinition);
12031203
llvm::Constant *getAddrOfWitnessTable(const NormalProtocolConformance *C,
1204-
ConstantInit definition = ConstantInit());
1204+
ConstantInit definition = ConstantInit());
1205+
llvm::Constant *getAddrOfWitnessTablePattern(const NormalProtocolConformance *C,
1206+
ConstantInit definition = ConstantInit());
1207+
12051208
llvm::Constant *
12061209
getAddrOfGenericWitnessTableCache(const NormalProtocolConformance *C,
12071210
ForDefinition_t forDefinition);

lib/IRGen/Linking.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,9 @@ std::string LinkEntity::mangleAsString() const {
170170
return mangler.mangleProtocolWitnessTableAccessFunction(
171171
getProtocolConformance());
172172

173+
case Kind::ProtocolWitnessTablePattern:
174+
return mangler.mangleProtocolWitnessTablePattern(getProtocolConformance());
175+
173176
case Kind::ProtocolWitnessTableLazyAccessFunction:
174177
return mangler.mangleProtocolWitnessTableLazyAccessFunction(getType(),
175178
getProtocolConformance());

stdlib/public/runtime/ErrorObject.mm

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -229,22 +229,22 @@ static Class getSwiftNativeNSErrorClass() {
229229
// Swift source.
230230

231231
auto TheWitnessTable = SWIFT_LAZY_CONSTANT(dlsym(RTLD_DEFAULT,
232-
MANGLE_AS_STRING(MANGLE_SYM(So10CFErrorRefas5Error10FoundationWP))));
232+
MANGLE_AS_STRING(MANGLE_SYM(So10CFErrorRefas5Error10FoundationWa))));
233233
assert(TheWitnessTable &&
234234
"Foundation overlay not loaded, or 'CFError : Error' conformance "
235235
"not available");
236236

237-
return reinterpret_cast<const WitnessTable *>(TheWitnessTable);
237+
return reinterpret_cast<const SWIFT_CC(swift) WitnessTable *(*)()>(TheWitnessTable)();
238238
}
239239

240240
static const HashableWitnessTable *getNSErrorConformanceToHashable() {
241241
auto TheWitnessTable = SWIFT_LAZY_CONSTANT(dlsym(RTLD_DEFAULT,
242-
MANGLE_AS_STRING(MANGLE_SYM(So8NSObjectCs8Hashable10ObjectiveCWP))));
242+
MANGLE_AS_STRING(MANGLE_SYM(So8NSObjectCs8Hashable10ObjectiveCWa))));
243243
assert(TheWitnessTable &&
244244
"ObjectiveC overlay not loaded, or 'NSObject : Hashable' conformance "
245245
"not available");
246246

247-
return reinterpret_cast<const HashableWitnessTable *>(TheWitnessTable);
247+
return reinterpret_cast<const SWIFT_CC(swift) HashableWitnessTable *(*)()>(TheWitnessTable)();
248248
}
249249

250250
bool SwiftError::isPureNSError() const {

0 commit comments

Comments
 (0)