@@ -466,10 +466,15 @@ namespace {
466
466
// / spelling of the protocol type, as well as the locality in the file), but it
467
467
// / does work.
468
468
class InheritedProtocolCollector {
469
+ static const StringLiteral DummyProtocolName;
470
+
469
471
// / Protocols that will be included by the ASTPrinter without any extra work.
470
472
SmallVector<ProtocolDecl *, 8 > IncludedProtocols;
471
473
// / Protocols that will not be printed by the ASTPrinter.
472
474
SmallVector<ProtocolDecl *, 8 > ExtraProtocols;
475
+ // / Protocols that can be printed, but whose conformances are constrained with
476
+ // / something that \e can't be printed.
477
+ SmallVector<const ProtocolType *, 8 > ConditionalConformanceProtocols;
473
478
474
479
// / For each type in \p directlyInherited, classify the protocols it refers to
475
480
// / as included for printing or not, and record them in the appropriate
@@ -492,6 +497,23 @@ class InheritedProtocolCollector {
492
497
}
493
498
}
494
499
500
+ // / For each type in \p directlyInherited, record any protocols that we would
501
+ // / have printed in ConditionalConformanceProtocols.
502
+ void recordConditionalConformances (ArrayRef<TypeLoc> directlyInherited) {
503
+ for (TypeLoc inherited : directlyInherited) {
504
+ Type inheritedTy = inherited.getType ();
505
+ if (!inheritedTy || !inheritedTy->isExistentialType ())
506
+ continue ;
507
+
508
+ ExistentialLayout layout = inheritedTy->getExistentialLayout ();
509
+ for (ProtocolType *protoTy : layout.getProtocols ())
510
+ if (isPublicOrUsableFromInline (protoTy))
511
+ ConditionalConformanceProtocols.push_back (protoTy);
512
+ // FIXME: This ignores layout constraints, but currently we don't support
513
+ // any of those besides 'AnyObject'.
514
+ }
515
+ }
516
+
495
517
public:
496
518
using PerTypeMap = llvm::MapVector<const NominalTypeDecl *,
497
519
InheritedProtocolCollector>;
@@ -530,6 +552,21 @@ class InheritedProtocolCollector {
530
552
collectProtocols (map, member);
531
553
}
532
554
555
+ // / If \p D is an extension providing conditional conformances, record those
556
+ // / in \p map.
557
+ // /
558
+ // / \sa recordConditionalConformances
559
+ static void collectSkippedConditionalConformances (PerTypeMap &map,
560
+ const Decl *D) {
561
+ auto *extension = dyn_cast<ExtensionDecl>(D);
562
+ if (!extension || !extension->isConstrainedExtension ())
563
+ return ;
564
+
565
+ const NominalTypeDecl *nominal = extension->getExtendedNominal ();
566
+ map[nominal].recordConditionalConformances (extension->getInherited ());
567
+ // No recursion here because extensions are never nested.
568
+ }
569
+
533
570
// / If there were any public protocols that need to be printed (i.e. they
534
571
// / weren't conformed to explicitly or inherited by another printed protocol),
535
572
// / do so now by printing a dummy extension on \p nominal to \p out.
@@ -580,7 +617,40 @@ class InheritedProtocolCollector {
580
617
}, [&out] { out << " , " ; });
581
618
out << " {}\n " ;
582
619
}
620
+
621
+ // / If there were any conditional conformances that couldn't be printed,
622
+ // / make a dummy extension that conforms to all of them, constrained by a
623
+ // / fake protocol.
624
+ bool printInaccessibleConformanceExtensionIfNeeded (
625
+ raw_ostream &out, const PrintOptions &printOptions,
626
+ const NominalTypeDecl *nominal) const {
627
+ if (ConditionalConformanceProtocols.empty ())
628
+ return false ;
629
+ assert (nominal->isGenericContext ());
630
+
631
+ out << " extension " ;
632
+ nominal->getDeclaredType ().print (out, printOptions);
633
+ out << " : " ;
634
+ swift::interleave (ConditionalConformanceProtocols,
635
+ [&out, &printOptions](const ProtocolType *protoTy) {
636
+ protoTy->print (out, printOptions);
637
+ }, [&out] { out << " , " ; });
638
+ out << " where "
639
+ << nominal->getGenericParamsOfContext ()->getParams ().front ()->getName ()
640
+ << " : " << DummyProtocolName << " {}\n " ;
641
+ return true ;
642
+ }
643
+
644
+ // / Print a fake protocol declaration for use by
645
+ // / #printInaccessibleConformanceExtensionIfNeeded.
646
+ static void printDummyProtocolDeclaration (raw_ostream &out) {
647
+ out << " \n @usableFromInline\n internal protocol " << DummyProtocolName
648
+ << " {}\n " ;
649
+ }
583
650
};
651
+
652
+ const StringLiteral InheritedProtocolCollector::DummyProtocolName =
653
+ " _ConstraintThatIsNotPartOfTheAPIOfThisLibrary" ;
584
654
} // end anonymous namespace
585
655
586
656
bool swift::emitParseableInterface (raw_ostream &out,
@@ -597,8 +667,12 @@ bool swift::emitParseableInterface(raw_ostream &out,
597
667
SmallVector<Decl *, 16 > topLevelDecls;
598
668
M->getTopLevelDecls (topLevelDecls);
599
669
for (const Decl *D : topLevelDecls) {
600
- if (!D->shouldPrintInContext (printOptions))
670
+ if (!D->shouldPrintInContext (printOptions) ||
671
+ !printOptions.CurrentPrintabilityChecker ->shouldPrint (D, printOptions)){
672
+ InheritedProtocolCollector::collectSkippedConditionalConformances (
673
+ inheritedProtocolMap, D);
601
674
continue ;
675
+ }
602
676
603
677
D->print (out, printOptions);
604
678
out << " \n " ;
@@ -607,11 +681,18 @@ bool swift::emitParseableInterface(raw_ostream &out,
607
681
}
608
682
609
683
// Print dummy extensions for any protocols that were indirectly conformed to.
684
+ bool needDummyProtocolDeclaration = false ;
610
685
for (const auto &nominalAndCollector : inheritedProtocolMap) {
686
+ const NominalTypeDecl *nominal = nominalAndCollector.first ;
611
687
const InheritedProtocolCollector &collector = nominalAndCollector.second ;
612
- collector.printSynthesizedExtensionIfNeeded (out, printOptions,
613
- nominalAndCollector.first );
688
+ collector.printSynthesizedExtensionIfNeeded (out, printOptions, nominal);
689
+ needDummyProtocolDeclaration |=
690
+ collector.printInaccessibleConformanceExtensionIfNeeded (out,
691
+ printOptions,
692
+ nominal);
614
693
}
694
+ if (needDummyProtocolDeclaration)
695
+ InheritedProtocolCollector::printDummyProtocolDeclaration (out);
615
696
616
697
return false ;
617
698
}
0 commit comments