Skip to content

Commit 32fd274

Browse files
authored
Merge pull request #19391 from DougGregor/assoc-conformance-default-witnesses
[ABI] Associated conformance defaults
2 parents 165f658 + 12da7c6 commit 32fd274

31 files changed

+585
-122
lines changed

docs/ABI/Mangling.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@ types where the metadata itself has unknown layout.)
141141
global ::= protocol 'TL' // protocol requirements base descriptor
142142
global ::= assoc-type-name 'Tl' // associated type descriptor
143143
global ::= assoc-type-name 'TM' // default associated type witness accessor
144-
144+
global ::= type assoc-type-path protocol 'Tn' // associated conformance descriptor
145+
global ::= type assoc-type-path protocol 'TN' // default associated conformance witness accessor
145146

146147
REABSTRACT-THUNK-TYPE ::= 'R' // reabstraction thunk helper function
147148
REABSTRACT-THUNK-TYPE ::= 'r' // reabstraction thunk

include/swift/AST/Decl.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3979,6 +3979,19 @@ class ProtocolDecl final : public NominalTypeDecl {
39793979
/// Record the default witness for a requirement.
39803980
void setDefaultWitness(ValueDecl *requirement, Witness witness);
39813981

3982+
/// Returns the default associated conformance witness for an associated
3983+
/// type, or \c None if there is no default.
3984+
Optional<ProtocolConformanceRef> getDefaultAssociatedConformanceWitness(
3985+
CanType association,
3986+
ProtocolDecl *requirement) const;
3987+
3988+
/// Set the default associated conformance witness for the given
3989+
/// associated conformance.
3990+
void setDefaultAssociatedConformanceWitness(
3991+
CanType association,
3992+
ProtocolDecl *requirement,
3993+
ProtocolConformanceRef conformance);
3994+
39823995
/// Retrieve the name to use for this protocol when interoperating
39833996
/// with the Objective-C runtime.
39843997
StringRef getObjCRuntimeName(llvm::SmallVectorImpl<char> &buffer) const;

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1696,6 +1696,11 @@ ERROR(type_witness_objc_generic_parameter,none,
16961696
NOTE(witness_fix_access,none,
16971697
"mark the %0 as '%select{%error|fileprivate|internal|public|%error}1' to "
16981698
"satisfy the requirement", (DescriptiveDeclKind, AccessLevel))
1699+
WARNING(assoc_type_default_conformance_failed,none,
1700+
"default type %0 for associated type %1 does not satisfy constraint "
1701+
"%2: %3", (Type, DeclName, Type, Type))
1702+
NOTE(assoc_type_default_here,none,
1703+
"associated type %0 has default type %1 written here", (DeclName, Type))
16991704

17001705
ERROR(protocol_access,none,
17011706
"%select{protocol must be declared %select{"

include/swift/Demangling/DemangleNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ NODE(DispatchThunk)
211211
NODE(MethodDescriptor)
212212
NODE(ProtocolRequirementsBaseDescriptor)
213213
NODE(AssociatedConformanceDescriptor)
214+
NODE(DefaultAssociatedConformanceAccessor)
214215
NODE(AssociatedTypeDescriptor)
215216
NODE(ThrowsAnnotation)
216217
NODE(EmptyList)

include/swift/IRGen/Linking.h

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,11 @@ class LinkEntity {
213213
/// is stored in the data.
214214
AssociatedConformanceDescriptor,
215215

216+
/// A default accessor for an associated conformance of a protocol.
217+
/// The pointer is a ProtocolDecl*; the index of the associated conformance
218+
/// is stored in the data.
219+
DefaultAssociatedConformanceAccessor,
220+
216221
/// A function which returns the default type metadata for the associated
217222
/// type of a protocol. The secondary pointer is a ProtocolDecl*.
218223
/// The index of the associated type declaration is stored in the data.
@@ -795,14 +800,13 @@ class LinkEntity {
795800
}
796801

797802
static LinkEntity
798-
forAssociatedConformanceDescriptor(ProtocolDecl *proto,
799-
CanType associatedType,
800-
ProtocolDecl *associatedProtocol) {
803+
forAssociatedConformanceDescriptor(AssociatedConformance conformance) {
801804
LinkEntity entity;
802805
entity.setForProtocolAndAssociatedConformance(
803806
Kind::AssociatedConformanceDescriptor,
804-
proto, associatedType,
805-
associatedProtocol);
807+
conformance.getSourceProtocol(),
808+
conformance.getAssociation(),
809+
conformance.getAssociatedRequirement());
806810
return entity;
807811
}
808812

@@ -835,6 +839,17 @@ class LinkEntity {
835839
return entity;
836840
}
837841

842+
static LinkEntity
843+
forDefaultAssociatedConformanceAccessor(AssociatedConformance conformance) {
844+
LinkEntity entity;
845+
entity.setForProtocolAndAssociatedConformance(
846+
Kind::DefaultAssociatedConformanceAccessor,
847+
conformance.getSourceProtocol(),
848+
conformance.getAssociation(),
849+
conformance.getAssociatedRequirement());
850+
return entity;
851+
}
852+
838853
static LinkEntity forReflectionBuiltinDescriptor(CanType type) {
839854
LinkEntity entity;
840855
entity.setForType(Kind::ReflectionBuiltinDescriptor, type);
@@ -925,7 +940,8 @@ class LinkEntity {
925940
LINKENTITY_GET_FIELD(Data, AssociatedConformanceIndex));
926941
}
927942

928-
assert(getKind() == Kind::AssociatedConformanceDescriptor);
943+
assert(getKind() == Kind::AssociatedConformanceDescriptor ||
944+
getKind() == Kind::DefaultAssociatedConformanceAccessor);
929945
return getAssociatedConformanceByIndex(
930946
cast<ProtocolDecl>(getDecl()),
931947
LINKENTITY_GET_FIELD(Data, AssociatedConformanceIndex));

lib/AST/ASTContext.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,11 @@ FOR_KNOWN_FOUNDATION_TYPES(CACHE_FOUNDATION_DECL)
285285
llvm::DenseMap<std::pair<const ProtocolDecl *, AssociatedTypeDecl *>, Type>
286286
DefaultTypeWitnesses;
287287

288+
/// Default associated conformance witnesses for protocols.
289+
llvm::DenseMap<std::tuple<const ProtocolDecl *, CanType, ProtocolDecl *>,
290+
ProtocolConformanceRef>
291+
DefaultAssociatedConformanceWitnesses;
292+
288293
/// \brief Structure that captures data that is segregated into different
289294
/// arenas.
290295
struct Arena {
@@ -1709,6 +1714,32 @@ void ProtocolDecl::setDefaultTypeWitness(AssociatedTypeDecl *assocType,
17091714
(void)pair;
17101715
}
17111716

1717+
Optional<ProtocolConformanceRef>
1718+
ProtocolDecl::getDefaultAssociatedConformanceWitness(
1719+
CanType association,
1720+
ProtocolDecl *requirement) const {
1721+
auto &ctx = getASTContext();
1722+
auto found =
1723+
ctx.getImpl().DefaultAssociatedConformanceWitnesses.find(
1724+
std::make_tuple(this, association, requirement));
1725+
if (found == ctx.getImpl().DefaultAssociatedConformanceWitnesses.end())
1726+
return None;
1727+
1728+
return found->second;
1729+
}
1730+
1731+
void ProtocolDecl::setDefaultAssociatedConformanceWitness(
1732+
CanType association,
1733+
ProtocolDecl *requirement,
1734+
ProtocolConformanceRef conformance) {
1735+
auto &ctx = getASTContext();
1736+
auto pair = ctx.getImpl().DefaultAssociatedConformanceWitnesses.insert(
1737+
std::make_pair(std::make_tuple(this, association, requirement),
1738+
conformance));
1739+
assert(pair.second && "Already have a default associated conformance");
1740+
(void)pair;
1741+
}
1742+
17121743
bool ASTContext::canImportModule(std::pair<Identifier, SourceLoc> ModulePath) {
17131744
// If this module has already been successfully imported, it is importable.
17141745
if (getLoadedModule(ModulePath) != nullptr)

lib/AST/NameLookup.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,7 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC,
712712
};
713713

714714
if (Loc.isValid() &&
715+
DC->getParentSourceFile() &&
715716
DC->getParentSourceFile()->Kind != SourceFileKind::REPL &&
716717
Ctx.LangOpts.EnableASTScopeLookup) {
717718
// Find the source file in which we are performing the lookup.

lib/Demangling/Demangler.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1841,6 +1841,15 @@ NodePointer Demangler::demangleThunkOrSpecialization() {
18411841
protoTy, assocTypePath, requirementTy);
18421842
}
18431843

1844+
case 'N': {
1845+
NodePointer requirementTy = popProtocol();
1846+
auto assocTypePath = popAssocTypePath();
1847+
NodePointer protoTy = popNode(Node::Kind::Type);
1848+
return createWithChildren(
1849+
Node::Kind::DefaultAssociatedConformanceAccessor,
1850+
protoTy, assocTypePath, requirementTy);
1851+
}
1852+
18441853
case 'H':
18451854
case 'h': {
18461855
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
@@ -323,6 +323,7 @@ class NodePrinter {
323323
case Node::Kind::DeclContext:
324324
case Node::Kind::DefaultArgumentInitializer:
325325
case Node::Kind::DefaultAssociatedTypeMetadataAccessor:
326+
case Node::Kind::DefaultAssociatedConformanceAccessor:
326327
case Node::Kind::DependentAssociatedTypeRef:
327328
case Node::Kind::DependentGenericSignature:
328329
case Node::Kind::DependentGenericParamCount:
@@ -1564,6 +1565,14 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
15641565
Printer << ": ";
15651566
print(Node->getChild(2));
15661567
return nullptr;
1568+
case Node::Kind::DefaultAssociatedConformanceAccessor:
1569+
Printer << "default associated conformance accessor for ";
1570+
print(Node->getChild(0));
1571+
Printer << ".";
1572+
print(Node->getChild(1));
1573+
Printer << ": ";
1574+
print(Node->getChild(2));
1575+
return nullptr;
15671576
case Node::Kind::AssociatedTypeDescriptor:
15681577
Printer << "associated type descriptor for ";
15691578
print(Node->getChild(0));

lib/Demangling/OldRemangler.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -888,6 +888,10 @@ void Remangler::mangleAssociatedConformanceDescriptor(Node *node) {
888888
Out << "<associated-conformance-descriptor>";
889889
}
890890

891+
void Remangler::mangleDefaultAssociatedConformanceAccessor(Node *node) {
892+
Out << "<default-associated-conformance-descriptor>";
893+
}
894+
891895
void Remangler::mangleAssociatedTypeMetadataAccessor(Node *node) {
892896
Out << "Wt";
893897
mangleChildNodes(node); // protocol conformance, identifier

lib/Demangling/Remangler.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,11 @@ void Remangler::mangleAssociatedConformanceDescriptor(Node *node) {
579579
Buffer << "Tn";
580580
}
581581

582+
void Remangler::mangleDefaultAssociatedConformanceAccessor(Node *node) {
583+
mangleChildNodes(node);
584+
Buffer << "TN";
585+
}
586+
582587
void Remangler::mangleAssociatedTypeMetadataAccessor(Node *node) {
583588
mangleChildNodes(node); // protocol conformance, identifier
584589
Buffer << "Wt";

lib/IRGen/GenDecl.cpp

Lines changed: 23 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

@@ -3988,6 +3982,25 @@ IRGenModule::getAddrOfDefaultAssociatedTypeMetadataAccessFunction(
39883982
return entry;
39893983
}
39903984

3985+
llvm::Function *
3986+
IRGenModule::getAddrOfDefaultAssociatedConformanceAccessor(
3987+
AssociatedConformance requirement) {
3988+
auto forDefinition = ForDefinition;
3989+
3990+
LinkEntity entity =
3991+
LinkEntity::forDefaultAssociatedConformanceAccessor(requirement);
3992+
llvm::Function *&entry = GlobalFuncs[entity];
3993+
if (entry) {
3994+
if (forDefinition) updateLinkageForDefinition(*this, entry, entity);
3995+
return entry;
3996+
}
3997+
3998+
auto signature = getAssociatedTypeWitnessTableAccessFunctionSignature();
3999+
LinkInfo link = LinkInfo::get(*this, entity, forDefinition);
4000+
entry = createFunction(*this, link, signature);
4001+
return entry;
4002+
}
4003+
39914004
llvm::Function *
39924005
IRGenModule::getAddrOfContinuationPrototype(CanSILFunctionType fnType) {
39934006
LinkEntity entity = LinkEntity::forCoroutineContinuationPrototype(fnType);

lib/IRGen/GenMeta.cpp

Lines changed: 96 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,14 @@ namespace {
647647

648648
if (entry.isAssociatedConformance()) {
649649
auto flags = Flags(Flags::Kind::AssociatedConformanceAccessFunction);
650-
return { flags, nullptr };
650+
651+
// Look for a default witness.
652+
llvm::Constant *defaultImpl =
653+
findDefaultAssociatedConformanceWitness(
654+
entry.getAssociatedConformancePath(),
655+
entry.getAssociatedConformanceRequirement());
656+
657+
return { flags, defaultImpl };
651658
}
652659

653660
assert(entry.isFunction());
@@ -712,10 +719,12 @@ namespace {
712719
if (entry.isAssociatedConformance()) {
713720
// Define the associated conformance descriptor to point to the
714721
// current position in the protocol descriptor.
722+
AssociatedConformance conformance(
723+
Proto,
724+
entry.getAssociatedConformancePath(),
725+
entry.getAssociatedConformanceRequirement());
715726
IGM.defineAssociatedConformanceDescriptor(
716-
Proto,
717-
entry.getAssociatedConformancePath(),
718-
entry.getAssociatedConformanceRequirement(),
727+
conformance,
719728
B.getAddrOfCurrentPosition(IGM.ProtocolRequirementStructTy));
720729
}
721730

@@ -800,6 +809,89 @@ namespace {
800809
IGF.Builder.CreateRet(returnValue);
801810
return accessor;
802811
}
812+
813+
llvm::Constant *findDefaultAssociatedConformanceWitness(
814+
CanType association,
815+
ProtocolDecl *requirement) {
816+
if (!DefaultWitnesses) return nullptr;
817+
818+
for (auto &entry : DefaultWitnesses->getEntries()) {
819+
if (!entry.isValid() ||
820+
entry.getKind() != SILWitnessTable::AssociatedTypeProtocol ||
821+
entry.getAssociatedTypeProtocolWitness().Protocol != requirement ||
822+
entry.getAssociatedTypeProtocolWitness().Requirement != association)
823+
continue;
824+
825+
auto witness = entry.getAssociatedTypeProtocolWitness().Witness;
826+
return getDefaultAssociatedConformanceAccessFunction(
827+
AssociatedConformance(Proto, association, requirement),
828+
witness);
829+
}
830+
831+
return nullptr;
832+
}
833+
834+
llvm::Constant *getDefaultAssociatedConformanceAccessFunction(
835+
AssociatedConformance requirement,
836+
ProtocolConformanceRef conformance) {
837+
auto accessor =
838+
IGM.getAddrOfDefaultAssociatedConformanceAccessor(requirement);
839+
840+
IRGenFunction IGF(IGM, accessor);
841+
if (IGM.DebugInfo)
842+
IGM.DebugInfo->emitArtificialFunction(IGF, accessor);
843+
844+
Explosion parameters = IGF.collectParameters();
845+
846+
llvm::Value *associatedTypeMetadata = parameters.claimNext();
847+
llvm::Value *self = parameters.claimNext();
848+
llvm::Value *wtable = parameters.claimNext();
849+
850+
bool hasArchetype =
851+
!conformance.isConcrete() ||
852+
conformance.getConcrete()->getType()->hasArchetype();
853+
if (hasArchetype) {
854+
// Bind local Self type data from the metadata argument.
855+
CanType selfInContext =
856+
Proto->mapTypeIntoContext(Proto->getProtocolSelfType())
857+
->getCanonicalType();
858+
IGF.bindLocalTypeDataFromTypeMetadata(selfInContext, IsExact, self,
859+
MetadataState::Abstract);
860+
IGF.setUnscopedLocalTypeData(
861+
selfInContext,
862+
LocalTypeDataKind::forAbstractProtocolWitnessTable(Proto),
863+
wtable);
864+
865+
// Bind the associated type metadata.
866+
IGF.bindLocalTypeDataFromTypeMetadata(requirement.getAssociation(),
867+
IsExact,
868+
associatedTypeMetadata,
869+
MetadataState::Abstract);
870+
}
871+
872+
// For a concrete witness table, call it.
873+
ProtocolDecl *associatedProtocol = requirement.getAssociatedRequirement();
874+
if (conformance.isConcrete()) {
875+
auto conformanceI = &IGM.getConformanceInfo(associatedProtocol,
876+
conformance.getConcrete());
877+
auto returnValue = conformanceI->getTable(IGF, &associatedTypeMetadata);
878+
IGF.Builder.CreateRet(returnValue);
879+
return accessor;
880+
}
881+
882+
// For an abstract table, emit a reference to the witness table.
883+
CanType associatedTypeInContext
884+
= Proto->mapTypeIntoContext(requirement.getAssociation())
885+
->getCanonicalType();
886+
auto returnValue =
887+
emitArchetypeWitnessTableRef(
888+
IGF,
889+
cast<ArchetypeType>(associatedTypeInContext),
890+
associatedProtocol);
891+
IGF.Builder.CreateRet(returnValue);
892+
return accessor;
893+
}
894+
803895
void addAssociatedTypeNames() {
804896
std::string AssociatedTypeNames;
805897

0 commit comments

Comments
 (0)