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