1919#include " swift/AST/FileSystem.h"
2020#include " swift/AST/Module.h"
2121#include " swift/AST/ModuleNameLookup.h"
22+ #include " swift/AST/NameLookupRequests.h"
2223#include " swift/AST/ProtocolConformance.h"
24+ #include " swift/AST/TypeCheckRequests.h"
2325#include " swift/AST/TypeRepr.h"
2426#include " swift/Basic/STLExtras.h"
2527#include " swift/Frontend/Frontend.h"
@@ -570,13 +572,14 @@ class InheritedProtocolCollector {
570572 });
571573 }
572574
575+ // Preserve the behavior of previous implementations which formatted of
576+ // empty extensions compactly with '{}' on the same line.
577+ PrintOptions extensionPrintOptions = printOptions;
578+ extensionPrintOptions.PrintEmptyMembersOnSameLine = true ;
579+
573580 // Then walk the remaining ones, and see what we need to print.
574- // Note: We could do this in one pass, but the logic is easier to
575- // understand if we build up the list and then print it, even if it takes
576- // a bit more memory.
577581 // FIXME: This will pick the availability attributes from the first sight
578582 // of a protocol rather than the maximally available case.
579- SmallVector<ProtocolAndAvailability, 16 > protocolsToPrint;
580583 for (const auto &protoAndAvailability : ExtraProtocols) {
581584 auto proto = std::get<0 >(protoAndAvailability);
582585 auto availability = std::get<1 >(protoAndAvailability);
@@ -602,58 +605,64 @@ class InheritedProtocolCollector {
602605 if (isPublicOrUsableFromInline (inherited) &&
603606 conformanceDeclaredInModule (M, nominal, inherited) &&
604607 !M->isImportedImplementationOnly (inherited->getParentModule ())) {
605- protocolsToPrint.push_back (
606- ProtocolAndAvailability (inherited, availability, isUnchecked,
607- otherAttrs));
608+ auto protoAndAvailability = ProtocolAndAvailability (
609+ inherited, availability, isUnchecked, otherAttrs);
610+ printSynthesizedExtension (out, extensionPrintOptions, M, nominal,
611+ protoAndAvailability);
608612 return TypeWalker::Action::SkipChildren;
609613 }
610614
611615 return TypeWalker::Action::Continue;
612616 });
613617 }
614- if (protocolsToPrint.empty ())
615- return ;
616-
617- for (const auto &protoAndAvailability : protocolsToPrint) {
618- StreamPrinter printer (out);
619- auto proto = std::get<0 >(protoAndAvailability);
620- auto availability = std::get<1 >(protoAndAvailability);
621- auto isUnchecked = std::get<2 >(protoAndAvailability);
622- auto otherAttrs = std::get<3 >(protoAndAvailability);
623-
624- PrintOptions curPrintOptions = printOptions;
625- auto printBody = [&] {
626- // FIXME: Shouldn't this be an implicit conversion?
627- TinyPtrVector<const DeclAttribute *> attrs;
628- attrs.insert (attrs.end (), availability.begin (), availability.end ());
629- auto spiAttributes = proto->getAttrs ().getAttributes <SPIAccessControlAttr>();
630- attrs.insert (attrs.end (), spiAttributes.begin (), spiAttributes.end ());
631- attrs.insert (attrs.end (), otherAttrs.begin (), otherAttrs.end ());
632- DeclAttributes::print (printer, curPrintOptions, attrs);
633-
634- printer << " extension " ;
635- {
636- bool oldFullyQualifiedTypesIfAmbiguous =
637- curPrintOptions.FullyQualifiedTypesIfAmbiguous ;
638- curPrintOptions.FullyQualifiedTypesIfAmbiguous =
639- curPrintOptions.FullyQualifiedExtendedTypesIfAmbiguous ;
640- nominal->getDeclaredType ().print (printer, curPrintOptions);
641- curPrintOptions.FullyQualifiedTypesIfAmbiguous =
642- oldFullyQualifiedTypesIfAmbiguous;
643- }
644- printer << " : " ;
645-
646- if (isUnchecked)
647- printer << " @unchecked " ;
618+ }
648619
649- proto->getDeclaredInterfaceType ()->print (printer, curPrintOptions);
620+ // / Prints a dummy extension on \p nominal to \p out for a public conformance
621+ // / to the protocol contained by \p protoAndAvailability.
622+ static void
623+ printSynthesizedExtension (raw_ostream &out, const PrintOptions &printOptions,
624+ ModuleDecl *M, const NominalTypeDecl *nominal,
625+ ProtocolAndAvailability &protoAndAvailability) {
626+ StreamPrinter printer (out);
627+
628+ auto proto = std::get<0 >(protoAndAvailability);
629+ auto availability = std::get<1 >(protoAndAvailability);
630+ auto isUnchecked = std::get<2 >(protoAndAvailability);
631+ auto otherAttrs = std::get<3 >(protoAndAvailability);
632+
633+ // Create a synthesized ExtensionDecl for the conformance.
634+ ASTContext &ctx = M->getASTContext ();
635+ auto inherits = ctx.AllocateCopy (llvm::makeArrayRef (InheritedEntry (
636+ TypeLoc::withoutLoc (proto->getDeclaredInterfaceType ()), isUnchecked)));
637+ auto extension =
638+ ExtensionDecl::create (ctx, SourceLoc (), nullptr , inherits,
639+ nominal->getModuleScopeContext (), nullptr );
640+ extension->setImplicit ();
641+
642+ // Build up synthesized DeclAttributes for the extension.
643+ TinyPtrVector<const DeclAttribute *> attrs;
644+ attrs.insert (attrs.end (), availability.begin (), availability.end ());
645+ auto spiAttributes =
646+ proto->getAttrs ().getAttributes <SPIAccessControlAttr>();
647+ attrs.insert (attrs.end (), spiAttributes.begin (), spiAttributes.end ());
648+ attrs.insert (attrs.end (), otherAttrs.begin (), otherAttrs.end ());
649+
650+ // Since DeclAttributes is a linked list where each added attribute becomes
651+ // the head, we need to add these attributes in reverse order to reproduce
652+ // the order in which previous implementations printed these attributes.
653+ DeclAttributes declAttrs;
654+ for (auto attr = attrs.rbegin (), end = attrs.rend (); attr != end; ++attr) {
655+ declAttrs.add (const_cast <DeclAttribute *>(*attr));
656+ }
657+ extension->getAttrs () = declAttrs;
650658
651- printer << " {}" ;
652- };
659+ ctx.evaluator .cacheOutput (ExtendedTypeRequest{extension},
660+ nominal->getDeclaredType ());
661+ ctx.evaluator .cacheOutput (ExtendedNominalRequest{extension},
662+ const_cast <NominalTypeDecl *>(nominal));
653663
654- printBody ();
655- printer << " \n " ;
656- }
664+ extension->print (printer, printOptions);
665+ printer << " \n " ;
657666 }
658667
659668 // / If there were any conditional conformances that couldn't be printed,
0 commit comments