@@ -195,6 +195,13 @@ class MinimalConformances {
195
195
MutableTerm term, unsigned ruleID,
196
196
SmallVectorImpl<unsigned > &result) const ;
197
197
198
+ bool isConformanceRuleRecoverable (
199
+ llvm::SmallDenseSet<unsigned , 4 > &visited,
200
+ unsigned ruleID) const ;
201
+
202
+ bool isDerivedViaCircularConformanceRule (
203
+ const std::vector<SmallVector<unsigned , 2 >> &paths) const ;
204
+
198
205
bool isValidConformancePath (
199
206
llvm::SmallDenseSet<unsigned , 4 > &visited,
200
207
const llvm::SmallVectorImpl<unsigned > &path) const ;
@@ -601,57 +608,71 @@ void MinimalConformances::computeCandidateConformancePaths() {
601
608
}
602
609
}
603
610
604
- // / Determines if \p path can be expressed without any of the conformance
605
- // / rules appearing in \p redundantConformances, by possibly substituting
606
- // / any occurrences of the redundant rules with alternate definitions
607
- // / appearing in \p conformancePaths.
611
+ // / If \p ruleID is redundant, determines if it can be expressed without
612
+ // / without any of the conformance rules determined to be redundant so far.
608
613
// /
609
- // / The \p conformancePaths map sends conformance rules to a list of
610
- // / disjunctions, where each disjunction is a product of other conformance
611
- // / rules.
612
- bool MinimalConformances::isValidConformancePath (
614
+ // / If the rule is not redundant, determines if its parent path can
615
+ // / also be recovered.
616
+ bool MinimalConformances::isConformanceRuleRecoverable (
613
617
llvm::SmallDenseSet<unsigned , 4 > &visited,
614
- const llvm::SmallVectorImpl<unsigned > &path) const {
618
+ unsigned ruleID) const {
619
+ if (RedundantConformances.count (ruleID)) {
620
+ SWIFT_DEFER {
621
+ visited.erase (ruleID);
622
+ };
623
+ visited.insert (ruleID);
615
624
616
- for ( unsigned ruleID : path) {
617
- if (visited. count (ruleID) > 0 )
625
+ auto found = ConformancePaths. find (ruleID);
626
+ if (found == ConformancePaths. end () )
618
627
return false ;
619
628
620
- if (RedundantConformances.count (ruleID)) {
629
+ bool foundValidConformancePath = false ;
630
+ for (const auto &otherPath : found->second ) {
631
+ if (isValidConformancePath (visited, otherPath)) {
632
+ foundValidConformancePath = true ;
633
+ break ;
634
+ }
635
+ }
636
+
637
+ if (!foundValidConformancePath)
638
+ return false ;
639
+ } else {
640
+ auto found = ParentPaths.find (ruleID);
641
+ if (found != ParentPaths.end ()) {
621
642
SWIFT_DEFER {
622
643
visited.erase (ruleID);
623
644
};
624
645
visited.insert (ruleID);
625
646
626
- auto found = ConformancePaths.find (ruleID);
627
- if (found == ConformancePaths.end ())
647
+ // If 'req' is based on some other conformance requirement
648
+ // `T.[P.]A : Q', we want to make sure that we have a
649
+ // non-redundant derivation for 'T : P'.
650
+ if (!isValidConformancePath (visited, found->second ))
628
651
return false ;
652
+ }
653
+ }
629
654
630
- bool foundValidConformancePath = false ;
631
- for (const auto &otherPath : found->second ) {
632
- if (isValidConformancePath (visited, otherPath)) {
633
- foundValidConformancePath = true ;
634
- break ;
635
- }
636
- }
655
+ return true ;
656
+ }
637
657
638
- if (!foundValidConformancePath)
639
- return false ;
640
- } else {
641
- auto found = ParentPaths.find (ruleID);
642
- if (found != ParentPaths.end ()) {
643
- SWIFT_DEFER {
644
- visited.erase (ruleID);
645
- };
646
- visited.insert (ruleID);
647
-
648
- // If 'req' is based on some other conformance requirement
649
- // `T.[P.]A : Q', we want to make sure that we have a
650
- // non-redundant derivation for 'T : P'.
651
- if (!isValidConformancePath (visited, found->second ))
652
- return false ;
653
- }
654
- }
658
+ // / Determines if \p path can be expressed without any of the conformance
659
+ // / rules determined to be redundant so far, by possibly substituting
660
+ // / any occurrences of the redundant rules with alternate definitions
661
+ // / appearing in the set of known conformancePaths.
662
+ // /
663
+ // / The conformance path map sends conformance rules to a list of
664
+ // / disjunctions, where each disjunction is a product of other conformance
665
+ // / rules.
666
+ bool MinimalConformances::isValidConformancePath (
667
+ llvm::SmallDenseSet<unsigned , 4 > &visited,
668
+ const llvm::SmallVectorImpl<unsigned > &path) const {
669
+
670
+ for (unsigned ruleID : path) {
671
+ if (visited.count (ruleID) > 0 )
672
+ return false ;
673
+
674
+ if (!isConformanceRuleRecoverable (visited, ruleID))
675
+ return false ;
655
676
}
656
677
657
678
return true ;
@@ -786,12 +807,45 @@ void MinimalConformances::verifyMinimalConformanceEquations() const {
786
807
#endif
787
808
}
788
809
810
+ bool MinimalConformances::isDerivedViaCircularConformanceRule (
811
+ const std::vector<SmallVector<unsigned , 2 >> &paths) const {
812
+ for (const auto &path : paths) {
813
+ if (!path.empty () &&
814
+ System.getRule (path.back ()).isCircularConformanceRule ())
815
+ return true ;
816
+ }
817
+
818
+ return false ;
819
+ }
820
+
789
821
// / Find a set of minimal conformances by marking all non-minimal
790
822
// / conformances redundant.
791
823
// /
792
824
// / In the first pass, we only consider conformance requirements that are
793
825
// / made redundant by concrete conformances.
794
826
void MinimalConformances::computeMinimalConformances () {
827
+ // First, mark any concrete conformances derived via a circular
828
+ // conformance as redundant upfront. See the comment at the top of
829
+ // Rule::isCircularConformanceRule() for an explanation of this.
830
+ for (unsigned ruleID : ConformanceRules) {
831
+ auto found = ConformancePaths.find (ruleID);
832
+ if (found == ConformancePaths.end ())
833
+ continue ;
834
+
835
+ const auto &paths = found->second ;
836
+
837
+ if (System.getRule (ruleID).isProtocolConformanceRule ())
838
+ continue ;
839
+
840
+ if (isDerivedViaCircularConformanceRule (paths))
841
+ RedundantConformances.insert (ruleID);
842
+ }
843
+
844
+ // Now, visit each conformance rule, trying to make it redundant by
845
+ // deriving a path in terms of other non-redundant conformance rules.
846
+ //
847
+ // Note that the ConformanceRules vector is sorted in descending
848
+ // canonical term order, so less canonical rules are eliminated first.
795
849
for (unsigned ruleID : ConformanceRules) {
796
850
auto found = ConformancePaths.find (ruleID);
797
851
if (found == ConformancePaths.end ())
@@ -840,10 +894,7 @@ void MinimalConformances::verifyMinimalConformances() const {
840
894
// minimal conformances.
841
895
llvm::SmallDenseSet<unsigned , 4 > visited;
842
896
843
- llvm::SmallVector<unsigned , 1 > path;
844
- path.push_back (ruleID);
845
-
846
- if (!isValidConformancePath (visited, path)) {
897
+ if (!isConformanceRuleRecoverable (visited, ruleID)) {
847
898
llvm::errs () << " Redundant conformance is not recoverable:\n " ;
848
899
llvm::errs () << rule << " \n\n " ;
849
900
dumpMinimalConformanceEquations (llvm::errs ());
0 commit comments