diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst index 71a809066d5..cf331843d3a 100644 --- a/docs/ABI/Mangling.rst +++ b/docs/ABI/Mangling.rst @@ -141,7 +141,8 @@ types where the metadata itself has unknown layout.) global ::= protocol 'TL' // protocol requirements base descriptor global ::= assoc-type-name 'Tl' // associated type descriptor global ::= assoc-type-name 'TM' // default associated type witness accessor - + global ::= type assoc-type-path protocol 'Tn' // associated conformance descriptor + global ::= type assoc-type-path protocol 'TN' // default associated conformance witness accessor REABSTRACT-THUNK-TYPE ::= 'R' // reabstraction thunk helper function REABSTRACT-THUNK-TYPE ::= 'r' // reabstraction thunk diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index ff0ee4a8836..370dcf8dcb3 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -3979,6 +3979,19 @@ public: /// Record the default witness for a requirement. void setDefaultWitness(ValueDecl *requirement, Witness witness); + /// Returns the default associated conformance witness for an associated + /// type, or \c None if there is no default. + Optional getDefaultAssociatedConformanceWitness( + CanType association, + ProtocolDecl *requirement) const; + + /// Set the default associated conformance witness for the given + /// associated conformance. + void setDefaultAssociatedConformanceWitness( + CanType association, + ProtocolDecl *requirement, + ProtocolConformanceRef conformance); + /// Retrieve the name to use for this protocol when interoperating /// with the Objective-C runtime. StringRef getObjCRuntimeName(llvm::SmallVectorImpl &buffer) const; diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index e8653c310c8..d85dd41f48c 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1696,6 +1696,11 @@ ERROR(type_witness_objc_generic_parameter,none, NOTE(witness_fix_access,none, "mark the %0 as '%select{%error|fileprivate|internal|public|%error}1' to " "satisfy the requirement", (DescriptiveDeclKind, AccessLevel)) +WARNING(assoc_type_default_conformance_failed,none, + "default type %0 for associated type %1 does not satisfy constraint " + "%2: %3", (Type, DeclName, Type, Type)) +NOTE(assoc_type_default_here,none, + "associated type %0 has default type %1 written here", (DeclName, Type)) ERROR(protocol_access,none, "%select{protocol must be declared %select{" diff --git a/include/swift/Demangling/DemangleNodes.def b/include/swift/Demangling/DemangleNodes.def index cb1d6f3b1cc..ed283d66806 100644 --- a/include/swift/Demangling/DemangleNodes.def +++ b/include/swift/Demangling/DemangleNodes.def @@ -211,6 +211,7 @@ NODE(DispatchThunk) NODE(MethodDescriptor) NODE(ProtocolRequirementsBaseDescriptor) NODE(AssociatedConformanceDescriptor) +NODE(DefaultAssociatedConformanceAccessor) NODE(AssociatedTypeDescriptor) NODE(ThrowsAnnotation) NODE(EmptyList) diff --git a/include/swift/IRGen/Linking.h b/include/swift/IRGen/Linking.h index e5d486f8aee..2e99868ffd2 100644 --- a/include/swift/IRGen/Linking.h +++ b/include/swift/IRGen/Linking.h @@ -213,6 +213,11 @@ class LinkEntity { /// is stored in the data. AssociatedConformanceDescriptor, + /// A default accessor for an associated conformance of a protocol. + /// The pointer is a ProtocolDecl*; the index of the associated conformance + /// is stored in the data. + DefaultAssociatedConformanceAccessor, + /// A function which returns the default type metadata for the associated /// type of a protocol. The secondary pointer is a ProtocolDecl*. /// The index of the associated type declaration is stored in the data. @@ -795,14 +800,13 @@ public: } static LinkEntity - forAssociatedConformanceDescriptor(ProtocolDecl *proto, - CanType associatedType, - ProtocolDecl *associatedProtocol) { + forAssociatedConformanceDescriptor(AssociatedConformance conformance) { LinkEntity entity; entity.setForProtocolAndAssociatedConformance( Kind::AssociatedConformanceDescriptor, - proto, associatedType, - associatedProtocol); + conformance.getSourceProtocol(), + conformance.getAssociation(), + conformance.getAssociatedRequirement()); return entity; } @@ -835,6 +839,17 @@ public: return entity; } + static LinkEntity + forDefaultAssociatedConformanceAccessor(AssociatedConformance conformance) { + LinkEntity entity; + entity.setForProtocolAndAssociatedConformance( + Kind::DefaultAssociatedConformanceAccessor, + conformance.getSourceProtocol(), + conformance.getAssociation(), + conformance.getAssociatedRequirement()); + return entity; + } + static LinkEntity forReflectionBuiltinDescriptor(CanType type) { LinkEntity entity; entity.setForType(Kind::ReflectionBuiltinDescriptor, type); @@ -925,7 +940,8 @@ public: LINKENTITY_GET_FIELD(Data, AssociatedConformanceIndex)); } - assert(getKind() == Kind::AssociatedConformanceDescriptor); + assert(getKind() == Kind::AssociatedConformanceDescriptor || + getKind() == Kind::DefaultAssociatedConformanceAccessor); return getAssociatedConformanceByIndex( cast(getDecl()), LINKENTITY_GET_FIELD(Data, AssociatedConformanceIndex)); diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index ea0de37e329..b0cea9afc0d 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -285,6 +285,11 @@ FOR_KNOWN_FOUNDATION_TYPES(CACHE_FOUNDATION_DECL) llvm::DenseMap, Type> DefaultTypeWitnesses; + /// Default associated conformance witnesses for protocols. + llvm::DenseMap, + ProtocolConformanceRef> + DefaultAssociatedConformanceWitnesses; + /// \brief Structure that captures data that is segregated into different /// arenas. struct Arena { @@ -1709,6 +1714,32 @@ void ProtocolDecl::setDefaultTypeWitness(AssociatedTypeDecl *assocType, (void)pair; } +Optional +ProtocolDecl::getDefaultAssociatedConformanceWitness( + CanType association, + ProtocolDecl *requirement) const { + auto &ctx = getASTContext(); + auto found = + ctx.getImpl().DefaultAssociatedConformanceWitnesses.find( + std::make_tuple(this, association, requirement)); + if (found == ctx.getImpl().DefaultAssociatedConformanceWitnesses.end()) + return None; + + return found->second; +} + +void ProtocolDecl::setDefaultAssociatedConformanceWitness( + CanType association, + ProtocolDecl *requirement, + ProtocolConformanceRef conformance) { + auto &ctx = getASTContext(); + auto pair = ctx.getImpl().DefaultAssociatedConformanceWitnesses.insert( + std::make_pair(std::make_tuple(this, association, requirement), + conformance)); + assert(pair.second && "Already have a default associated conformance"); + (void)pair; +} + bool ASTContext::canImportModule(std::pair ModulePath) { // If this module has already been successfully imported, it is importable. if (getLoadedModule(ModulePath) != nullptr) diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index 34aeb911dcb..699a8b766c3 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -712,6 +712,7 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC, }; if (Loc.isValid() && + DC->getParentSourceFile() && DC->getParentSourceFile()->Kind != SourceFileKind::REPL && Ctx.LangOpts.EnableASTScopeLookup) { // Find the source file in which we are performing the lookup. diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp index a41f9784560..9048834b24f 100644 --- a/lib/Demangling/Demangler.cpp +++ b/lib/Demangling/Demangler.cpp @@ -1841,6 +1841,15 @@ NodePointer Demangler::demangleThunkOrSpecialization() { protoTy, assocTypePath, requirementTy); } + case 'N': { + NodePointer requirementTy = popProtocol(); + auto assocTypePath = popAssocTypePath(); + NodePointer protoTy = popNode(Node::Kind::Type); + return createWithChildren( + Node::Kind::DefaultAssociatedConformanceAccessor, + protoTy, assocTypePath, requirementTy); + } + case 'H': case 'h': { auto nodeKind = c == 'H' ? Node::Kind::KeyPathEqualsThunkHelper diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp index 50e451bff0f..363d552faab 100644 --- a/lib/Demangling/NodePrinter.cpp +++ b/lib/Demangling/NodePrinter.cpp @@ -323,6 +323,7 @@ private: case Node::Kind::DeclContext: case Node::Kind::DefaultArgumentInitializer: case Node::Kind::DefaultAssociatedTypeMetadataAccessor: + case Node::Kind::DefaultAssociatedConformanceAccessor: case Node::Kind::DependentAssociatedTypeRef: case Node::Kind::DependentGenericSignature: case Node::Kind::DependentGenericParamCount: @@ -1564,6 +1565,14 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) { Printer << ": "; print(Node->getChild(2)); return nullptr; + case Node::Kind::DefaultAssociatedConformanceAccessor: + Printer << "default associated conformance accessor for "; + print(Node->getChild(0)); + Printer << "."; + print(Node->getChild(1)); + Printer << ": "; + print(Node->getChild(2)); + return nullptr; case Node::Kind::AssociatedTypeDescriptor: Printer << "associated type descriptor for "; print(Node->getChild(0)); diff --git a/lib/Demangling/OldRemangler.cpp b/lib/Demangling/OldRemangler.cpp index 2549d1a04bf..e4f08eeb659 100644 --- a/lib/Demangling/OldRemangler.cpp +++ b/lib/Demangling/OldRemangler.cpp @@ -888,6 +888,10 @@ void Remangler::mangleAssociatedConformanceDescriptor(Node *node) { Out << ""; } +void Remangler::mangleDefaultAssociatedConformanceAccessor(Node *node) { + Out << ""; +} + void Remangler::mangleAssociatedTypeMetadataAccessor(Node *node) { Out << "Wt"; mangleChildNodes(node); // protocol conformance, identifier diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp index f7ffe88252d..348b288130f 100644 --- a/lib/Demangling/Remangler.cpp +++ b/lib/Demangling/Remangler.cpp @@ -579,6 +579,11 @@ void Remangler::mangleAssociatedConformanceDescriptor(Node *node) { Buffer << "Tn"; } +void Remangler::mangleDefaultAssociatedConformanceAccessor(Node *node) { + mangleChildNodes(node); + Buffer << "TN"; +} + void Remangler::mangleAssociatedTypeMetadataAccessor(Node *node) { mangleChildNodes(node); // protocol conformance, identifier Buffer << "Wt"; diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index d48d0294270..0cc89afd7e4 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -3389,21 +3389,15 @@ llvm::GlobalValue *IRGenModule::defineAssociatedTypeDescriptor( llvm::Constant *IRGenModule::getAddrOfAssociatedConformanceDescriptor( AssociatedConformance conformance) { - auto entity = LinkEntity::forAssociatedConformanceDescriptor( - conformance.getSourceProtocol(), - conformance.getAssociation(), - conformance.getAssociatedRequirement()); + auto entity = LinkEntity::forAssociatedConformanceDescriptor(conformance); return getAddrOfLLVMVariable(entity, getPointerAlignment(), ConstantInit(), ProtocolRequirementStructTy, DebugTypeInfo()); } llvm::GlobalValue *IRGenModule::defineAssociatedConformanceDescriptor( - ProtocolDecl *proto, - CanType subject, - ProtocolDecl *requirement, - llvm::Constant *definition) { - auto entity = LinkEntity::forAssociatedConformanceDescriptor(proto, subject, - requirement); + AssociatedConformance conformance, + llvm::Constant *definition) { + auto entity = LinkEntity::forAssociatedConformanceDescriptor(conformance); return defineAlias(entity, definition); } @@ -3988,6 +3982,25 @@ IRGenModule::getAddrOfDefaultAssociatedTypeMetadataAccessFunction( return entry; } +llvm::Function * +IRGenModule::getAddrOfDefaultAssociatedConformanceAccessor( + AssociatedConformance requirement) { + auto forDefinition = ForDefinition; + + LinkEntity entity = + LinkEntity::forDefaultAssociatedConformanceAccessor(requirement); + llvm::Function *&entry = GlobalFuncs[entity]; + if (entry) { + if (forDefinition) updateLinkageForDefinition(*this, entry, entity); + return entry; + } + + auto signature = getAssociatedTypeWitnessTableAccessFunctionSignature(); + LinkInfo link = LinkInfo::get(*this, entity, forDefinition); + entry = createFunction(*this, link, signature); + return entry; +} + llvm::Function * IRGenModule::getAddrOfContinuationPrototype(CanSILFunctionType fnType) { LinkEntity entity = LinkEntity::forCoroutineContinuationPrototype(fnType); diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index f0198cfa31d..a75abe04fe7 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -647,7 +647,14 @@ namespace { if (entry.isAssociatedConformance()) { auto flags = Flags(Flags::Kind::AssociatedConformanceAccessFunction); - return { flags, nullptr }; + + // Look for a default witness. + llvm::Constant *defaultImpl = + findDefaultAssociatedConformanceWitness( + entry.getAssociatedConformancePath(), + entry.getAssociatedConformanceRequirement()); + + return { flags, defaultImpl }; } assert(entry.isFunction()); @@ -712,10 +719,12 @@ namespace { if (entry.isAssociatedConformance()) { // Define the associated conformance descriptor to point to the // current position in the protocol descriptor. + AssociatedConformance conformance( + Proto, + entry.getAssociatedConformancePath(), + entry.getAssociatedConformanceRequirement()); IGM.defineAssociatedConformanceDescriptor( - Proto, - entry.getAssociatedConformancePath(), - entry.getAssociatedConformanceRequirement(), + conformance, B.getAddrOfCurrentPosition(IGM.ProtocolRequirementStructTy)); } @@ -800,6 +809,89 @@ namespace { IGF.Builder.CreateRet(returnValue); return accessor; } + + llvm::Constant *findDefaultAssociatedConformanceWitness( + CanType association, + ProtocolDecl *requirement) { + if (!DefaultWitnesses) return nullptr; + + for (auto &entry : DefaultWitnesses->getEntries()) { + if (!entry.isValid() || + entry.getKind() != SILWitnessTable::AssociatedTypeProtocol || + entry.getAssociatedTypeProtocolWitness().Protocol != requirement || + entry.getAssociatedTypeProtocolWitness().Requirement != association) + continue; + + auto witness = entry.getAssociatedTypeProtocolWitness().Witness; + return getDefaultAssociatedConformanceAccessFunction( + AssociatedConformance(Proto, association, requirement), + witness); + } + + return nullptr; + } + + llvm::Constant *getDefaultAssociatedConformanceAccessFunction( + AssociatedConformance requirement, + ProtocolConformanceRef conformance) { + auto accessor = + IGM.getAddrOfDefaultAssociatedConformanceAccessor(requirement); + + IRGenFunction IGF(IGM, accessor); + if (IGM.DebugInfo) + IGM.DebugInfo->emitArtificialFunction(IGF, accessor); + + Explosion parameters = IGF.collectParameters(); + + llvm::Value *associatedTypeMetadata = parameters.claimNext(); + llvm::Value *self = parameters.claimNext(); + llvm::Value *wtable = parameters.claimNext(); + + bool hasArchetype = + !conformance.isConcrete() || + conformance.getConcrete()->getType()->hasArchetype(); + if (hasArchetype) { + // Bind local Self type data from the metadata argument. + CanType selfInContext = + Proto->mapTypeIntoContext(Proto->getProtocolSelfType()) + ->getCanonicalType(); + IGF.bindLocalTypeDataFromTypeMetadata(selfInContext, IsExact, self, + MetadataState::Abstract); + IGF.setUnscopedLocalTypeData( + selfInContext, + LocalTypeDataKind::forAbstractProtocolWitnessTable(Proto), + wtable); + + // Bind the associated type metadata. + IGF.bindLocalTypeDataFromTypeMetadata(requirement.getAssociation(), + IsExact, + associatedTypeMetadata, + MetadataState::Abstract); + } + + // For a concrete witness table, call it. + ProtocolDecl *associatedProtocol = requirement.getAssociatedRequirement(); + if (conformance.isConcrete()) { + auto conformanceI = &IGM.getConformanceInfo(associatedProtocol, + conformance.getConcrete()); + auto returnValue = conformanceI->getTable(IGF, &associatedTypeMetadata); + IGF.Builder.CreateRet(returnValue); + return accessor; + } + + // For an abstract table, emit a reference to the witness table. + CanType associatedTypeInContext + = Proto->mapTypeIntoContext(requirement.getAssociation()) + ->getCanonicalType(); + auto returnValue = + emitArchetypeWitnessTableRef( + IGF, + cast(associatedTypeInContext), + associatedProtocol); + IGF.Builder.CreateRet(returnValue); + return accessor; + } + void addAssociatedTypeNames() { std::string AssociatedTypeNames; diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp index 0cf4f020ec3..a04e8ae4344 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -1385,6 +1385,13 @@ llvm::Value *uniqueForeignWitnessTableRef(IRGenFunction &IGF, void addAssociatedConformance(AssociatedConformance requirement) { // FIXME: Add static witness tables for type conformances. + auto &entry = SILEntries.front(); + (void)entry; + SILEntries = SILEntries.slice(1); + + if (ResilientConformance) + return; + auto associate = ConformanceInContext.getAssociatedType( requirement.getAssociation())->getCanonicalType(); @@ -1394,9 +1401,8 @@ llvm::Value *uniqueForeignWitnessTableRef(IRGenFunction &IGF, requirement.getAssociation(), requirement.getAssociatedRequirement()); + #ifndef NDEBUG - auto &entry = SILEntries.front(); - (void)entry; assert(entry.getKind() == SILWitnessTable::AssociatedTypeProtocol && "sil witness table does not match protocol"); auto associatedWitness = entry.getAssociatedTypeProtocolWitness(); @@ -1411,8 +1417,6 @@ llvm::Value *uniqueForeignWitnessTableRef(IRGenFunction &IGF, "offset doesn't match ProtocolInfo layout"); #endif - SILEntries = SILEntries.slice(1); - llvm::Constant *wtableAccessFunction = getAssociatedTypeWitnessTableAccessFunction(requirement, associate, @@ -1644,7 +1648,8 @@ llvm::Constant *WitnessTableBuilder:: getAssociatedTypeWitnessTableAccessFunction(AssociatedConformance requirement, CanType associatedType, ProtocolConformanceRef associatedConformance) { - if (!associatedType->hasArchetype()) { + bool hasArchetype = associatedType->hasArchetype(); + if (!hasArchetype && !ResilientConformance) { assert(associatedConformance.isConcrete() && "no concrete conformance for non-dependent type"); return getOrCreateWitnessTableAccessFunction(IGM, @@ -1682,13 +1687,6 @@ getAssociatedTypeWitnessTableAccessFunction(AssociatedConformance requirement, Address destTable(parameters.claimNext(), IGM.getPointerAlignment()); setProtocolWitnessTableName(IGM, destTable.getAddress(), ConcreteType, Conformance.getProtocol()); - IGF.bindLocalTypeDataFromSelfWitnessTable( - &Conformance, - destTable.getAddress(), - [&](CanType type) { - return Conformance.getDeclContext()->mapTypeIntoContext(type) - ->getCanonicalType(); - }); ProtocolDecl *associatedProtocol = requirement.getAssociatedRequirement(); @@ -1710,6 +1708,24 @@ getAssociatedTypeWitnessTableAccessFunction(AssociatedConformance requirement, } } + // If there are no archetypes, return a reference to the table. There is + // no need for a cache. + if (!hasArchetype) { + auto wtable = MetadataResponse::forComplete( + conformanceI->getTable(IGF, &associatedTypeMetadata)) + .getMetadata(); + IGF.Builder.CreateRet(wtable); + return accessor; + } + + IGF.bindLocalTypeDataFromSelfWitnessTable( + &Conformance, + destTable.getAddress(), + [&](CanType type) { + return Conformance.getDeclContext()->mapTypeIntoContext(type) + ->getCanonicalType(); + }); + // If the witness table is directly fulfillable from the type, // we don't need a cache entry. // TODO: maybe we should have a cache entry anyway if the fulfillment @@ -1869,7 +1885,8 @@ llvm::Constant *WitnessTableBuilder::emitResilientWitnessTable() { unsigned count = 0; for (auto &entry : SILWT->getEntries()) { if (entry.getKind() != SILWitnessTable::Method && - entry.getKind() != SILWitnessTable::AssociatedType) + entry.getKind() != SILWitnessTable::AssociatedType && + entry.getKind() != SILWitnessTable::AssociatedTypeProtocol) continue; count++; @@ -1907,6 +1924,36 @@ llvm::Constant *WitnessTableBuilder::emitResilientWitnessTable() { continue; } + // Associated conformance access function. + if (entry.getKind() == SILWitnessTable::AssociatedTypeProtocol) { + const auto &witness = entry.getAssociatedTypeProtocolWitness(); + + // Associated type descriptor. + AssociatedConformance requirement(SILWT->getConformance()->getProtocol(), + witness.Requirement, + witness.Protocol); + auto assocConformanceDescriptor = + IGM.getAddrOfLLVMVariableOrGOTEquivalent( + LinkEntity::forAssociatedConformanceDescriptor(requirement), + Alignment(4), IGM.ProtocolRequirementStructTy); + table.addRelativeAddress(assocConformanceDescriptor); + + auto associate = + ConformanceInContext.getAssociatedType( + witness.Requirement)->getCanonicalType(); + + ProtocolConformanceRef associatedConformance = + ConformanceInContext.getAssociatedConformance(witness.Requirement, + witness.Protocol); + + llvm::Constant *wtableAccessFunction = + getAssociatedTypeWitnessTableAccessFunction(requirement, + associate, + associatedConformance); + table.addRelativeAddress(wtableAccessFunction); + continue; + } + if (entry.getKind() != SILWitnessTable::Method) continue; diff --git a/lib/IRGen/IRGenMangler.h b/lib/IRGen/IRGenMangler.h index edd77135904..37c5b953481 100644 --- a/lib/IRGen/IRGenMangler.h +++ b/lib/IRGen/IRGenMangler.h @@ -197,6 +197,19 @@ public: return finalize(); } + std::string mangleDefaultAssociatedConformanceAccessor( + const ProtocolDecl *proto, + CanType subject, + const ProtocolDecl *requirement) { + beginMangling(); + appendAnyGenericType(proto); + bool isFirstAssociatedTypeIdentifier = true; + appendAssociatedTypePath(subject, isFirstAssociatedTypeIdentifier); + appendProtocolName(requirement); + appendOperator("TN"); + return finalize(); + } + std::string mangleProtocolConformanceDescriptor( const ProtocolConformance *Conformance) { beginMangling(); diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index fb33001d795..0c98b828d44 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -1237,10 +1237,8 @@ public: llvm::Constant *getAddrOfAssociatedConformanceDescriptor( AssociatedConformance conformance); llvm::GlobalValue *defineAssociatedConformanceDescriptor( - ProtocolDecl *proto, - CanType subject, - ProtocolDecl *requirement, - llvm::Constant *definition); + AssociatedConformance conformance, + llvm::Constant *definition); llvm::Constant *getAddrOfProtocolDescriptor(ProtocolDecl *D, ConstantInit definition = ConstantInit()); @@ -1293,6 +1291,8 @@ public: const AssociatedConformance &association); llvm::Function *getAddrOfDefaultAssociatedTypeMetadataAccessFunction( AssociatedType association); + llvm::Function *getAddrOfDefaultAssociatedConformanceAccessor( + AssociatedConformance requirement); Address getAddrOfObjCISAMask(); diff --git a/lib/IRGen/Linking.cpp b/lib/IRGen/Linking.cpp index 6562b5093ac..b24a2470ce0 100644 --- a/lib/IRGen/Linking.cpp +++ b/lib/IRGen/Linking.cpp @@ -187,6 +187,14 @@ std::string LinkEntity::mangleAsString() const { assocConformance.second); } + case Kind::DefaultAssociatedConformanceAccessor: { + auto assocConformance = getAssociatedConformance(); + return mangler.mangleDefaultAssociatedConformanceAccessor( + cast(getDecl()), + assocConformance.first, + assocConformance.second); + } + case Kind::ProtocolConformanceDescriptor: return mangler.mangleProtocolConformanceDescriptor( cast(getProtocolConformance())); @@ -498,6 +506,7 @@ SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const { case Kind::AssociatedTypeMetadataAccessFunction: case Kind::DefaultAssociatedTypeMetadataAccessFunction: case Kind::AssociatedTypeWitnessTableAccessFunction: + case Kind::DefaultAssociatedConformanceAccessor: case Kind::GenericProtocolWitnessTableCache: case Kind::GenericProtocolWitnessTableInstantiationFunction: return SILLinkage::Private; @@ -629,6 +638,7 @@ bool LinkEntity::isAvailableExternally(IRGenModule &IGM) const { case Kind::TypeMetadataCompletionFunction: case Kind::TypeMetadataPattern: case Kind::DefaultAssociatedTypeMetadataAccessFunction: + case Kind::DefaultAssociatedConformanceAccessor: return false; case Kind::ValueWitness: diff --git a/lib/ParseSIL/ParseSIL.cpp b/lib/ParseSIL/ParseSIL.cpp index e655e141137..75d0bc763a3 100644 --- a/lib/ParseSIL/ParseSIL.cpp +++ b/lib/ParseSIL/ParseSIL.cpp @@ -181,7 +181,8 @@ namespace { ProtocolConformance * parseProtocolConformanceHelper(ProtocolDecl *&proto, GenericEnvironment *GenericEnv, - bool localScope); + bool localScope, + ProtocolDecl *defaultForProto); public: SILParser(Parser &P) : P(P), SILMod(static_cast(P.SIL)->M), @@ -391,15 +392,18 @@ namespace { bool isStartOfSILInstruction(); bool parseSubstitutions(SmallVectorImpl &parsed, - GenericEnvironment *GenericEnv=nullptr); + GenericEnvironment *GenericEnv=nullptr, + ProtocolDecl *defaultForProto = nullptr); ProtocolConformance *parseProtocolConformance(ProtocolDecl *&proto, GenericEnvironment *&genericEnv, - bool localScope); - ProtocolConformance *parseProtocolConformance() { + bool localScope, + ProtocolDecl *defaultForProto); + ProtocolConformance *parseProtocolConformance( + ProtocolDecl *defaultForProto) { ProtocolDecl *dummy; GenericEnvironment *env; - return parseProtocolConformance(dummy, env, true); + return parseProtocolConformance(dummy, env, true, defaultForProto); } Optional @@ -1012,6 +1016,8 @@ bool SILParser::performTypeLocChecking(TypeLoc &T, bool IsSILType, if (!DC) DC = &P.SF; + else if (!GenericEnv) + GenericEnv = DC->getGenericEnvironmentOfContext(); return swift::performTypeLocChecking(P.Context, T, /*isSILMode=*/true, IsSILType, @@ -1510,10 +1516,46 @@ bool SILParser::parseSILBBArgsAtBranch(SmallVector &Args, return false; } +/// Bind any unqualified 'Self' references to the given protocol's 'Self' +/// generic parameter. +/// +/// FIXME: This is a hack to work around the lack of a DeclContext for +/// witness tables. +static void bindProtocolSelfInTypeRepr(TypeLoc &TL, ProtocolDecl *proto) { + if (auto typeRepr = TL.getTypeRepr()) { + // AST walker to update 'Self' references. + class BindProtocolSelf : public ASTWalker { + ProtocolDecl *proto; + GenericTypeParamDecl *selfParam; + Identifier selfId; + + public: + BindProtocolSelf(ProtocolDecl *proto) + : proto(proto), + selfParam(proto->getProtocolSelfType()->getDecl()), + selfId(proto->getASTContext().Id_Self) { + } + + virtual bool walkToTypeReprPre(TypeRepr *T) override { + if (auto ident = dyn_cast(T)) { + auto firstComponent = ident->getComponentRange().front(); + if (firstComponent->getIdentifier() == selfId) + firstComponent->setValue(selfParam, proto); + } + + return true; + } + }; + + typeRepr->walk(BindProtocolSelf(proto)); + } +} + /// Parse the substitution list for an apply instruction or /// specialized protocol conformance. bool SILParser::parseSubstitutions(SmallVectorImpl &parsed, - GenericEnvironment *GenericEnv) { + GenericEnvironment *GenericEnv, + ProtocolDecl *defaultForProto) { // Check for an opening '<' bracket. if (!P.Tok.isContextualPunctuator("<")) return false; @@ -1529,7 +1571,10 @@ bool SILParser::parseSubstitutions(SmallVectorImpl &parsed, if (TyR.isNull()) return true; TypeLoc Ty = TyR.get(); - if (performTypeLocChecking(Ty, /*IsSILType=*/ false, GenericEnv)) + if (defaultForProto) + bindProtocolSelfInTypeRepr(Ty, defaultForProto); + if (performTypeLocChecking(Ty, /*IsSILType=*/ false, GenericEnv, + defaultForProto)) return true; parsed.push_back({Loc, Ty.getType()}); } while (P.consumeIf(tok::comma)); @@ -5725,7 +5770,8 @@ static NormalProtocolConformance *parseNormalProtocolConformance(Parser &P, ProtocolConformance *SILParser::parseProtocolConformance( ProtocolDecl *&proto, GenericEnvironment *&genericEnv, - bool localScope) { + bool localScope, + ProtocolDecl *defaultForProto) { // Parse generic params for the protocol conformance. We need to make sure // they have the right scope. Optional GenericsScope; @@ -5741,7 +5787,8 @@ ProtocolConformance *SILParser::parseProtocolConformance( } ProtocolConformance *retVal = - parseProtocolConformanceHelper(proto, genericEnv, localScope); + parseProtocolConformanceHelper(proto, genericEnv, localScope, + defaultForProto); if (localScope) { GenericsScope.reset(); @@ -5752,13 +5799,19 @@ ProtocolConformance *SILParser::parseProtocolConformance( ProtocolConformance *SILParser::parseProtocolConformanceHelper( ProtocolDecl *&proto, GenericEnvironment *witnessEnv, - bool localScope) { + bool localScope, + ProtocolDecl *defaultForProto) { // Parse AST type. ParserResult TyR = P.parseType(); if (TyR.isNull()) return nullptr; TypeLoc Ty = TyR.get(); - if (performTypeLocChecking(Ty, /*IsSILType=*/ false, witnessEnv)) + if (defaultForProto) { + bindProtocolSelfInTypeRepr(Ty, defaultForProto); + } + + if (performTypeLocChecking(Ty, /*IsSILType=*/ false, witnessEnv, + defaultForProto)) return nullptr; auto ConformingTy = Ty.getType(); @@ -5770,7 +5823,7 @@ ProtocolConformance *SILParser::parseProtocolConformanceHelper( // Parse substitutions for specialized conformance. SmallVector parsedSubs; - if (parseSubstitutions(parsedSubs, witnessEnv)) + if (parseSubstitutions(parsedSubs, witnessEnv, defaultForProto)) return nullptr; if (P.parseToken(tok::l_paren, diag::expected_sil_witness_lparen)) @@ -5778,7 +5831,8 @@ ProtocolConformance *SILParser::parseProtocolConformanceHelper( ProtocolDecl *dummy; GenericEnvironment *specializedEnv; auto genericConform = - parseProtocolConformance(dummy, specializedEnv, localScope); + parseProtocolConformance(dummy, specializedEnv, localScope, + defaultForProto); if (!genericConform) return nullptr; if (P.parseToken(tok::r_paren, diag::expected_sil_witness_rparen)) @@ -5799,7 +5853,7 @@ ProtocolConformance *SILParser::parseProtocolConformanceHelper( if (P.parseToken(tok::l_paren, diag::expected_sil_witness_lparen)) return nullptr; - auto baseConform = parseProtocolConformance(); + auto baseConform = parseProtocolConformance(defaultForProto); if (!baseConform) return nullptr; if (P.parseToken(tok::r_paren, diag::expected_sil_witness_rparen)) @@ -5812,41 +5866,6 @@ ProtocolConformance *SILParser::parseProtocolConformanceHelper( return retVal; } -/// Bind any unqualified 'Self' references to the given protocol's 'Self' -/// generic parameter. -/// -/// FIXME: This is a hack to work around the lack of a DeclContext for -/// witness tables. -static void bindProtocolSelfInTypeRepr(TypeLoc &TL, ProtocolDecl *proto) { - if (auto typeRepr = TL.getTypeRepr()) { - // AST walker to update 'Self' references. - class BindProtocolSelf : public ASTWalker { - ProtocolDecl *proto; - GenericTypeParamDecl *selfParam; - Identifier selfId; - - public: - BindProtocolSelf(ProtocolDecl *proto) - : proto(proto), - selfParam(proto->getProtocolSelfType()->getDecl()), - selfId(proto->getASTContext().Id_Self) { - } - - virtual bool walkToTypeReprPre(TypeRepr *T) override { - if (auto ident = dyn_cast(T)) { - auto firstComponent = ident->getComponentRange().front(); - if (firstComponent->getIdentifier() == selfId) - firstComponent->setValue(selfParam, proto); - } - - return true; - } - }; - - typeRepr->walk(BindProtocolSelf(proto)); - } -} - /// Parser a single SIL vtable entry and add it to either \p witnessEntries /// or \c conditionalConformances. static bool parseSILVTableEntry( @@ -5859,6 +5878,7 @@ static bool parseSILVTableEntry( std::vector &witnessEntries, std::vector &conditionalConformances) { + ProtocolDecl *defaultForProto = isDefaultWitnessTable ? proto : nullptr; Identifier EntryKeyword; SourceLoc KeywordLoc; if (P.parseIdentifier(EntryKeyword, KeywordLoc, @@ -5878,7 +5898,8 @@ static bool parseSILVTableEntry( return true; if (P.parseToken(tok::colon, diag::expected_sil_witness_colon)) return true; - ProtocolConformance *conform = witnessState.parseProtocolConformance(); + ProtocolConformance *conform = + witnessState.parseProtocolConformance(defaultForProto); if (!conform) // Ignore this witness entry for now. return false; @@ -5925,7 +5946,7 @@ static bool parseSILVTableEntry( ProtocolConformanceRef conformance(proto); if (P.Tok.getText() != "dependent") { - auto concrete = witnessState.parseProtocolConformance(); + auto concrete = witnessState.parseProtocolConformance(defaultForProto); if (!concrete) // Ignore this witness entry for now. return false; conformance = ProtocolConformanceRef(concrete); @@ -6045,7 +6066,8 @@ bool SILParserTUState::parseSILWitnessTable(Parser &P) { GenericEnvironment *witnessEnv; auto conf = WitnessState.parseProtocolConformance(proto, witnessEnv, - false/*localScope*/); + false/*localScope*/, + nullptr); WitnessState.ContextGenericEnv = witnessEnv; NormalProtocolConformance *theConformance = conf ? diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp index 135002631f9..4182f48e035 100644 --- a/lib/SILGen/SILGenType.cpp +++ b/lib/SILGen/SILGenType.cpp @@ -769,7 +769,19 @@ public: } void addAssociatedConformance(const AssociatedConformance &req) { - addMissingDefault(); + auto witness = + Proto->getDefaultAssociatedConformanceWitness( + req.getAssociation(), + req.getAssociatedRequirement()); + if (!witness) + return addMissingDefault(); + + auto entry = + SILWitnessTable::AssociatedTypeProtocolWitness{ + req.getAssociation(), + req.getAssociatedRequirement(), + *witness}; + DefaultWitnesses.push_back(entry); } }; diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 9cc6860adbf..4b1f7a56346 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -5252,6 +5252,30 @@ void DefaultWitnessChecker::recordWitness( void TypeChecker::inferDefaultWitnesses(ProtocolDecl *proto) { DefaultWitnessChecker checker(*this, proto); + // Find the default for the given associated type. + auto findAssociatedTypeDefault = + [&](AssociatedTypeDecl *assocType, + AssociatedTypeDecl **defaultedAssocTypeOut = nullptr) -> Type { + auto defaultedAssocType = + AssociatedTypeInference::findDefaultedAssociatedType(*this, assocType); + if (!defaultedAssocType) + return nullptr;; + + Type defaultType = defaultedAssocType->getDefaultDefinitionLoc().getType(); + if (!defaultType) + return nullptr; + + // Map out of its protocol context... + defaultType = defaultType->mapTypeOutOfContext(); + if (defaultType->hasError()) + return nullptr; + + if (defaultedAssocTypeOut) + *defaultedAssocTypeOut = defaultedAssocType; + + return defaultType; + }; + for (auto *requirement : proto->getMembers()) { if (requirement->isInvalid()) continue; @@ -5262,19 +5286,8 @@ void TypeChecker::inferDefaultWitnesses(ProtocolDecl *proto) { if (auto assocType = dyn_cast(valueDecl)) { if (assocType->getOverriddenDecls().empty()) { - if (auto defaultedAssocType = - AssociatedTypeInference::findDefaultedAssociatedType( - *this, assocType)) { - Type defaultType = - defaultedAssocType->getDefaultDefinitionLoc().getType(); - - // Map out of its protocol context... - defaultType = defaultType->mapTypeOutOfContext(); - - if (!defaultType->hasError()) { - proto->setDefaultTypeWitness(assocType, defaultType); - } - } + if (Type defaultType = findAssociatedTypeDefault(assocType)) + proto->setDefaultTypeWitness(assocType, defaultType); } continue; @@ -5288,6 +5301,77 @@ void TypeChecker::inferDefaultWitnesses(ProtocolDecl *proto) { checker.resolveWitnessViaLookup(valueDecl); } + + // Find defaults for any associated conformances rooted on defaulted + // associated types. + for (const auto &req : proto->getRequirementSignature()) { + if (req.getKind() != RequirementKind::Conformance) + continue; + if (req.getFirstType()->isEqual(proto->getProtocolSelfType())) + continue; + + // Find the innermost dependent member type (e.g., Self.AssocType), so + // we can look at the associated type. + auto depMemTy = req.getFirstType()->getAs(); + if (!depMemTy) + continue; + + while (auto innerDepMemTy = + depMemTy->getBase()->getAs()) + depMemTy = innerDepMemTy; + + if (!depMemTy->getBase()->isEqual(proto->getProtocolSelfType())) + continue; + + auto assocType = depMemTy->getAssocType(); + if (!assocType) + continue; + + // Find the associated type nearest our own protocol, which might have + // a default not available in the associated type referenced by the + // (canonicalized) requirement. + if (assocType->getProtocol() != proto) { + SmallVector found; + proto->getModuleContext()->lookupQualified( + proto, assocType->getFullName(), + NL_QualifiedDefault|NL_ProtocolMembers|NL_OnlyTypes, + found); + if (found.size() == 1 && isa(found[0])) + assocType = cast(found[0]); + } + + // Dig out the default associated type definition. + AssociatedTypeDecl *defaultedAssocType = nullptr; + Type defaultAssocType = findAssociatedTypeDefault(assocType, + &defaultedAssocType); + if (!defaultAssocType) + continue; + + Type defaultAssocTypeInContext = + proto->mapTypeIntoContext(defaultAssocType); + auto requirementProto = + req.getSecondType()->castTo()->getDecl(); + auto conformance = conformsToProtocol(defaultAssocTypeInContext, + requirementProto, proto, + ConformanceCheckFlags::Used); + if (!conformance) { + // Diagnose the lack of a conformance. This is potentially an ABI + // incompatibility. + diagnose(proto, diag::assoc_type_default_conformance_failed, + defaultAssocType, assocType->getFullName(), req.getFirstType(), + req.getSecondType()); + diagnose(defaultedAssocType, diag::assoc_type_default_here, + assocType->getFullName(), defaultAssocType) + .highlight( + defaultedAssocType->getDefaultDefinitionLoc().getSourceRange()); + + continue; + } + + // Record the default associated conformance. + proto->setDefaultAssociatedConformanceWitness( + req.getFirstType()->getCanonicalType(), requirementProto, *conformance); + } } void TypeChecker::recordKnownWitness(NormalProtocolConformance *conformance, diff --git a/lib/TBDGen/TBDGen.cpp b/lib/TBDGen/TBDGen.cpp index 68e0d42ffd9..3d693e5106a 100644 --- a/lib/TBDGen/TBDGen.cpp +++ b/lib/TBDGen/TBDGen.cpp @@ -100,11 +100,8 @@ void TBDGenVisitor::addAssociatedTypeDescriptor(AssociatedTypeDecl *assocType) { } void TBDGenVisitor::addAssociatedConformanceDescriptor( - ProtocolDecl *proto, - CanType subject, - ProtocolDecl *requirement) { - auto entity = LinkEntity::forAssociatedConformanceDescriptor(proto, subject, - requirement); + AssociatedConformance conformance) { + auto entity = LinkEntity::forAssociatedConformanceDescriptor(conformance); addSymbol(entity); } @@ -426,10 +423,11 @@ void TBDGenVisitor::visitProtocolDecl(ProtocolDecl *PD) { if (req.getFirstType()->isEqual(PD->getProtocolSelfType())) continue; - addAssociatedConformanceDescriptor( - PD, - req.getFirstType()->getCanonicalType(), - req.getSecondType()->castTo()->getDecl()); + AssociatedConformance conformance( + PD, + req.getFirstType()->getCanonicalType(), + req.getSecondType()->castTo()->getDecl()); + addAssociatedConformanceDescriptor(conformance); } for (auto *member : PD->getMembers()) { diff --git a/lib/TBDGen/TBDGenVisitor.h b/lib/TBDGen/TBDGenVisitor.h index 9db482ea1ad..e4682652e7e 100644 --- a/lib/TBDGen/TBDGenVisitor.h +++ b/lib/TBDGen/TBDGenVisitor.h @@ -66,9 +66,7 @@ private: void addProtocolRequirementsBaseDescriptor(ProtocolDecl *proto); void addAssociatedTypeDescriptor(AssociatedTypeDecl *assocType); - void addAssociatedConformanceDescriptor(ProtocolDecl *proto, - CanType subject, - ProtocolDecl *requirement); + void addAssociatedConformanceDescriptor(AssociatedConformance conformance); public: TBDGenVisitor(tapi::internal::InterfaceFile &symbols, diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp index 993c5d7aa24..0bd3a26270e 100644 --- a/stdlib/public/runtime/Metadata.cpp +++ b/stdlib/public/runtime/Metadata.cpp @@ -3657,9 +3657,9 @@ static void initializeResilientWitnessTable(GenericWitnessTable *genericTable, case ProtocolRequirementFlags::Kind::ReadCoroutine: case ProtocolRequirementFlags::Kind::ModifyCoroutine: case ProtocolRequirementFlags::Kind::AssociatedTypeAccessFunction: + case ProtocolRequirementFlags::Kind::AssociatedConformanceAccessFunction: break; case ProtocolRequirementFlags::Kind::BaseProtocol: - case ProtocolRequirementFlags::Kind::AssociatedConformanceAccessFunction: continue; } diff --git a/test/Demangle/Inputs/manglings.txt b/test/Demangle/Inputs/manglings.txt index 35fe8a3acfb..57244a99ede 100644 --- a/test/Demangle/Inputs/manglings.txt +++ b/test/Demangle/Inputs/manglings.txt @@ -332,3 +332,4 @@ A.h(A) -> ()inlined generic function <(A, A1)> of $S1T19protocol_resilience17ResilientProtocolPTl --> associated type descriptor for T $S18resilient_protocol21ResilientBaseProtocolTL --> protocol requirements base descriptor for resilient_protocol.ResilientBaseProtocol $S1t1PP10AssocType2_AA1QTn --> associated conformance descriptor for t.P.AssocType2: t.Q +$S1t1PP10AssocType2_AA1QTN --> default associated conformance accessor for t.P.AssocType2: t.Q diff --git a/test/IRGen/protocol_resilience_descriptors.swift b/test/IRGen/protocol_resilience_descriptors.swift index 7dd512ee44c..5f6c8caf979 100644 --- a/test/IRGen/protocol_resilience_descriptors.swift +++ b/test/IRGen/protocol_resilience_descriptors.swift @@ -14,6 +14,7 @@ // Protocol descriptor // CHECK-DEFINITION-LABEL: @"$S18resilient_protocol29ProtocolWithAssocTypeDefaultsMp" ={{( protected)?}} constant +// CHECK-DEFINITION-SAME: @"$S18resilient_protocol29ProtocolWithAssocTypeDefaultsP2T2_AA014OtherResilientC0TN" // CHECK-DEFINITION-SAME: $S2T118resilient_protocol29ProtocolWithAssocTypeDefaultsPTM // CHECK-DEFINITION-SAME: $S2T218resilient_protocol29ProtocolWithAssocTypeDefaultsPTM @@ -25,6 +26,9 @@ // CHECK-DEFINITION: @"$S1T18resilient_protocol24ProtocolWithRequirementsPTl" ={{( dllexport)?}}{{( protected)?}} alias // CHECK-DEFINITION: @"$S18resilient_protocol29ProtocolWithAssocTypeDefaultsP2T2_AA014OtherResilientC0Tn" ={{( dllexport)?}}{{( protected)?}} alias +// Default associated conformance witnesses +// CHECK-DEFINITION-LABEL: define internal swiftcc i8** @"$S18resilient_protocol29ProtocolWithAssocTypeDefaultsP2T2_AA014OtherResilientC0TN" + // Default associated type witnesses // CHECK-DEFINITION-LABEL: define internal swiftcc %swift.metadata_response @"$S2T118resilient_protocol29ProtocolWithAssocTypeDefaultsPTM" @@ -32,6 +36,8 @@ // CHECK-DEFINITION: getelementptr inbounds i8*, i8** [[WTABLE:%.*]], i32 2 // CHECK-DEFINITION: call{{.*}}S18resilient_protocol7WrapperVMa +// CHECK-DEFINITION-LABEL: define internal swiftcc %swift.metadata_response @"$S9AssocType18resilient_protocol20ResilientSelfDefaultPTM + import resilient_protocol // ---------------------------------------------------------------------------- @@ -51,6 +57,12 @@ public protocol P { } public struct ConditionallyConforms { } public struct Y { } +// CHECK-USAGE: @"$S31protocol_resilience_descriptors29ConformsWithAssocRequirementsV010resilient_A008ProtocoleF12TypeDefaultsAAWr" = internal +// CHECK-USAGE-SAME: $S18resilient_protocol29ProtocolWithAssocTypeDefaultsP2T2_AA014OtherResilientC0Tn +// CHECK-USAGE-SAME: $S31protocol_resilience_descriptors29ConformsWithAssocRequirementsV010resilient_A008ProtocoleF12TypeDefaultsAA2T2_AD014OtherResilientI0PWT +public struct ConformsWithAssocRequirements : ProtocolWithAssocTypeDefaults { +} + // CHECK-USAGE: @"$Sx1T_MXA" = // CHECK-USAGE-SAME: i32 0 // CHECK-USAGE-SAME: @"{{got.|__imp_}}$S18resilient_protocol24ProtocolWithRequirementsMp" diff --git a/test/Inputs/resilient_protocol.swift b/test/Inputs/resilient_protocol.swift index e6dfcb8dd76..9a93674a092 100644 --- a/test/Inputs/resilient_protocol.swift +++ b/test/Inputs/resilient_protocol.swift @@ -34,3 +34,7 @@ public protocol ProtocolWithAssocTypeDefaults { associatedtype T1 = Self associatedtype T2: OtherResilientProtocol = Wrapper } + +public protocol ResilientSelfDefault : ResilientBaseProtocol { + associatedtype AssocType: ResilientBaseProtocol = Self +} diff --git a/test/SIL/Parser/default_witness_tables.sil b/test/SIL/Parser/default_witness_tables.sil index bb1b8e9cccb..8153e21675a 100644 --- a/test/SIL/Parser/default_witness_tables.sil +++ b/test/SIL/Parser/default_witness_tables.sil @@ -48,7 +48,7 @@ bb0(%0 : $*Self): // CHECK-LABEL: sil_default_witness_table ResilientProtocol { -// CHECK: no_default +// CHECK: associated_type_protocol (T: Proto): Wrapper: specialize ( Wrapper: Proto module witness_tables) // CHECK: associated_type T: Wrapper // CHECK: no_default // CHECK: no_default @@ -58,7 +58,7 @@ bb0(%0 : $*Self): // CHECK: } sil_default_witness_table ResilientProtocol { - no_default + associated_type_protocol (T: Proto): Wrapper: specialize ( Wrapper: Proto module witness_tables) associated_type T: Wrapper no_default no_default diff --git a/test/SILGen/protocol_resilience.swift b/test/SILGen/protocol_resilience.swift index e930bfbf77b..e75df7e57bd 100644 --- a/test/SILGen/protocol_resilience.swift +++ b/test/SILGen/protocol_resilience.swift @@ -251,6 +251,13 @@ func inoutResilientProtocol(_ x: inout OtherConformingType) { inoutFunc(&OtherConformingType.staticPropertyInExtension) } +// Protocol is public -- needs resilient witness table +public struct ConformsToP: P { } + +public protocol ResilientAssocTypes { + associatedtype AssocType: P = ConformsToP +} + // CHECK-LABEL: sil_default_witness_table P { // CHECK-NEXT: } @@ -312,3 +319,8 @@ func inoutResilientProtocol(_ x: inout OtherConformingType) { // CHECK-NEXT: method #ReabstractSelfRefined.callback!setter.1: {{.*}} : @$S19protocol_resilience21ReabstractSelfRefinedP8callbackyxxcvs // CHECK-NEXT: method #ReabstractSelfRefined.callback!modify.1: {{.*}} : @$S19protocol_resilience21ReabstractSelfRefinedP8callbackyxxcvM // CHECK-NEXT: } + +// CHECK-LABEL: sil_default_witness_table ResilientAssocTypes { +// CHECK-NEXT: associated_type_protocol (AssocType: P): ConformsToP: P module protocol_resilience +// CHECK-NEXT: associated_type AssocType: ConformsToP +// CHECK-NEXT: } diff --git a/test/decl/protocol/resilient_defaults.swift b/test/decl/protocol/resilient_defaults.swift new file mode 100644 index 00000000000..b959241bae5 --- /dev/null +++ b/test/decl/protocol/resilient_defaults.swift @@ -0,0 +1,18 @@ +// RUN: %target-typecheck-verify-swift -enable-resilience + +public struct Wrapper: P { } +extension Wrapper: Q where T: Q { } + +public protocol PBase { + associatedtype AssocType +} + +public protocol P: PBase { + override associatedtype AssocType: P = Wrapper + // expected-note@-1{{associated type 'AssocType' has default type 'Wrapper' written here}} +} + +public protocol Q: P where Self.AssocType: Q { } + +public protocol R: Q where Self.AssocType: R { } +// expected-warning@-1{{default type 'Wrapper' for associated type 'AssocType' does not satisfy constraint 'Self.AssocType': 'R'}} diff --git a/validation-test/Evolution/Inputs/protocol_add_requirements.swift b/validation-test/Evolution/Inputs/protocol_add_requirements.swift index 6e2eb344e6f..81cfc38581a 100644 --- a/validation-test/Evolution/Inputs/protocol_add_requirements.swift +++ b/validation-test/Evolution/Inputs/protocol_add_requirements.swift @@ -176,7 +176,15 @@ public func doSomething(_ t: inout T, k1: T.Key, k2: T #endif } -public struct Wrapper { } +public protocol SimpleProtocol { + static func getString() -> String +} + +public struct Wrapper: SimpleProtocol { + public static func getString() -> String { + return "I am a wrapper for \(T.self)" + } +} public protocol AddAssocTypesProtocol { // FIXME: The presence of a single method requirement causes us to @@ -185,7 +193,7 @@ public protocol AddAssocTypesProtocol { #if AFTER associatedtype AssocType = Self - associatedtype AssocType2 = Wrapper + associatedtype AssocType2: SimpleProtocol = Wrapper #endif } @@ -193,7 +201,6 @@ extension AddAssocTypesProtocol { public func dummy() { } } - public func doSomethingWithAssocTypes(_ value: T) -> String { #if AFTER @@ -202,3 +209,17 @@ public func doSomethingWithAssocTypes(_ value: T) return "there are no associated types yet" #endif } + +public func doSomethingWithAssocConformances(_ value: T) + -> String { +#if AFTER + let at2: Any.Type = T.AssocType2.self + if let simpleType = at2 as? SimpleProtocol.Type { + return simpleType.getString() + } + + return "missing associated conformance" +#else + return "there are no associated conformances yet" +#endif +} diff --git a/validation-test/Evolution/test_protocol_add_requirements.swift b/validation-test/Evolution/test_protocol_add_requirements.swift index 046b6ee59e4..2acfb7e81d3 100644 --- a/validation-test/Evolution/test_protocol_add_requirements.swift +++ b/validation-test/Evolution/test_protocol_add_requirements.swift @@ -154,5 +154,16 @@ ProtocolAddRequirementsTest.test("AddAssociatedTypeRequirements") { } } +ProtocolAddRequirementsTest.test("AddAssociatedConformanceRequirements") { + let addString = AddAssociatedType() + let stringResult = doSomethingWithAssocConformances(addString) + + if getVersion() == 0 { + expectEqual("there are no associated conformances yet", stringResult) + } else { + expectEqual("I am a wrapper for AddAssociatedType", stringResult) + } +} + runAllTests()