diff --git a/lib/Frontend/ParseableInterfaceSupport.cpp b/lib/Frontend/ParseableInterfaceSupport.cpp index fe06f771260..5ff58c89e30 100644 --- a/lib/Frontend/ParseableInterfaceSupport.cpp +++ b/lib/Frontend/ParseableInterfaceSupport.cpp @@ -17,6 +17,7 @@ #include "swift/AST/ExistentialLayout.h" #include "swift/AST/FileSystem.h" #include "swift/AST/Module.h" +#include "swift/AST/ProtocolConformance.h" #include "swift/Frontend/Frontend.h" #include "swift/Frontend/ParseableInterfaceSupport.h" #include "swift/Frontend/PrintingDiagnosticConsumer.h" @@ -657,12 +658,26 @@ public: // No recursion here because extensions are never nested. } + /// Returns true if the conformance of \p nominal to \p proto is declared in + /// module \p M. + static bool conformanceDeclaredInModule(ModuleDecl *M, + const NominalTypeDecl *nominal, + ProtocolDecl *proto) { + SmallVector conformances; + nominal->lookupConformance(M, proto, conformances); + return llvm::all_of(conformances, + [M](const ProtocolConformance *conformance) -> bool { + return M == conformance->getDeclContext()->getParentModule(); + }); + } + /// If there were any public protocols that need to be printed (i.e. they /// weren't conformed to explicitly or inherited by another printed protocol), /// do so now by printing a dummy extension on \p nominal to \p out. void printSynthesizedExtensionIfNeeded(raw_ostream &out, const PrintOptions &printOptions, + ModuleDecl *M, const NominalTypeDecl *nominal) const { if (ExtraProtocols.empty()) return; @@ -688,10 +703,13 @@ public: [&](ProtocolDecl *inherited) -> TypeWalker::Action { if (!handledProtocols.insert(inherited).second) return TypeWalker::Action::SkipChildren; - if (isPublicOrUsableFromInline(inherited)) { + + if (isPublicOrUsableFromInline(inherited) && + conformanceDeclaredInModule(M, nominal, inherited)) { protocolsToPrint.push_back(inherited); return TypeWalker::Action::SkipChildren; } + return TypeWalker::Action::Continue; }); } @@ -775,7 +793,7 @@ bool swift::emitParseableInterface(raw_ostream &out, for (const auto &nominalAndCollector : inheritedProtocolMap) { const NominalTypeDecl *nominal = nominalAndCollector.first; const InheritedProtocolCollector &collector = nominalAndCollector.second; - collector.printSynthesizedExtensionIfNeeded(out, printOptions, nominal); + collector.printSynthesizedExtensionIfNeeded(out, printOptions, M, nominal); needDummyProtocolDeclaration |= collector.printInaccessibleConformanceExtensionIfNeeded(out, printOptions, diff --git a/test/ParseableInterface/conformances.swift b/test/ParseableInterface/conformances.swift index 6d16469f95b..566cf6d083d 100644 --- a/test/ParseableInterface/conformances.swift +++ b/test/ParseableInterface/conformances.swift @@ -167,6 +167,7 @@ extension MultiGeneric: PublicProto where U: PrivateProto {} // CHECK: public struct MultiGeneric { // CHECK-END: extension conformances.MultiGeneric : PublicProto where T : _ConstraintThatIsNotPartOfTheAPIOfThisLibrary {} + internal struct InternalImpl_BAD: PrivateSubProto {} internal struct InternalImplConstrained_BAD {} extension InternalImplConstrained_BAD: PublicProto where T: PublicProto {} @@ -182,5 +183,12 @@ extension WrapperForInternal.InternalImplConstrained_BAD: PublicProto where T: P extension WrapperForInternal.InternalImplConstrained2_BAD: PublicProto where T: PrivateProto {} +internal protocol ExtraHashable: Hashable {} +extension Bool: ExtraHashable {} + +// NEGATIVE-NOT: extension {{(Swift.)?}}Bool{{.+}}Hashable +// NEGATIVE-NOT: extension {{(Swift.)?}}Bool{{.+}}Equatable + + // CHECK-END: @usableFromInline // CHECK-END-NEXT: internal protocol _ConstraintThatIsNotPartOfTheAPIOfThisLibrary {}