@@ -195,6 +195,13 @@ class MinimalConformances {
195195 MutableTerm term, unsigned ruleID,
196196 SmallVectorImpl<unsigned > &result) const ;
197197
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+
198205 bool isValidConformancePath (
199206 llvm::SmallDenseSet<unsigned , 4 > &visited,
200207 const llvm::SmallVectorImpl<unsigned > &path) const ;
@@ -601,57 +608,71 @@ void MinimalConformances::computeCandidateConformancePaths() {
601608 }
602609}
603610
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.
608613// /
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 (
613617 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);
615624
616- for ( unsigned ruleID : path) {
617- if (visited. count (ruleID) > 0 )
625+ auto found = ConformancePaths. find (ruleID);
626+ if (found == ConformancePaths. end () )
618627 return false ;
619628
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 ()) {
621642 SWIFT_DEFER {
622643 visited.erase (ruleID);
623644 };
624645 visited.insert (ruleID);
625646
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 ))
628651 return false ;
652+ }
653+ }
629654
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+ }
637657
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 ;
655676 }
656677
657678 return true ;
@@ -786,12 +807,45 @@ void MinimalConformances::verifyMinimalConformanceEquations() const {
786807#endif
787808}
788809
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+
789821// / Find a set of minimal conformances by marking all non-minimal
790822// / conformances redundant.
791823// /
792824// / In the first pass, we only consider conformance requirements that are
793825// / made redundant by concrete conformances.
794826void 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.
795849 for (unsigned ruleID : ConformanceRules) {
796850 auto found = ConformancePaths.find (ruleID);
797851 if (found == ConformancePaths.end ())
@@ -840,10 +894,7 @@ void MinimalConformances::verifyMinimalConformances() const {
840894 // minimal conformances.
841895 llvm::SmallDenseSet<unsigned , 4 > visited;
842896
843- llvm::SmallVector<unsigned , 1 > path;
844- path.push_back (ruleID);
845-
846- if (!isValidConformancePath (visited, path)) {
897+ if (!isConformanceRuleRecoverable (visited, ruleID)) {
847898 llvm::errs () << " Redundant conformance is not recoverable:\n " ;
848899 llvm::errs () << rule << " \n\n " ;
849900 dumpMinimalConformanceEquations (llvm::errs ());
0 commit comments