6565using namespace swift ;
6666using namespace rewriting ;
6767
68- // / Recompute Useful, RulesInEmptyContext, ProjectionCount and DecomposeCount
69- // / if needed.
68+ // / Recompute various cached values if needed.
7069void RewriteLoop::recompute (const RewriteSystem &system) {
7170 if (!Dirty)
7271 return ;
7372 Dirty = 0 ;
7473
74+ Useful = 0 ;
7575 ProjectionCount = 0 ;
7676 DecomposeCount = 0 ;
77- Useful = false ;
77+ HasConcreteTypeAliasRule = 0 ;
7878
7979 RewritePathEvaluator evaluator (Basepoint);
8080 for (auto step : Path) {
8181 switch (step.Kind ) {
82- case RewriteStep::Rule:
82+ case RewriteStep::Rule: {
8383 Useful |= (!step.isInContext () && !evaluator.isInContext ());
84+
85+ const auto &rule = system.getRule (step.getRuleID ());
86+ if (rule.isProtocolTypeAliasRule () &&
87+ rule.getLHS ().size () == 3 )
88+ HasConcreteTypeAliasRule = 1 ;
89+
8490 break ;
91+ }
8592
8693 case RewriteStep::LeftConcreteProjection:
8794 ++ProjectionCount;
@@ -130,6 +137,14 @@ unsigned RewriteLoop::getDecomposeCount(
130137 return DecomposeCount;
131138}
132139
140+ // / Returns true if the loop contains at least one concrete protocol typealias rule,
141+ // / which have the form ([P].A.[concrete: C] => [P].A).
142+ bool RewriteLoop::hasConcreteTypeAliasRule (
143+ const RewriteSystem &system) const {
144+ const_cast <RewriteLoop *>(this )->recompute (system);
145+ return HasConcreteTypeAliasRule;
146+ }
147+
133148// / The number of Decompose steps, used by the elimination order to prioritize
134149// / loops that are not concrete simplifications.
135150bool RewriteLoop::isUseful (
@@ -488,7 +503,7 @@ RewritePath::getRulesInEmptyContext(const MutableTerm &term,
488503// / \p redundantConformances equal to the set of conformance rules that are
489504// / not minimal conformances.
490505Optional<std::pair<unsigned , unsigned >> RewriteSystem::
491- findRuleToDelete (llvm::function_ref< bool ( unsigned )> isRedundantRuleFn) {
506+ findRuleToDelete (EliminationPredicate isRedundantRuleFn) {
492507 SmallVector<std::pair<unsigned , unsigned >, 2 > redundancyCandidates;
493508 for (unsigned loopID : indices (Loops)) {
494509 auto &loop = Loops[loopID];
@@ -520,7 +535,10 @@ findRuleToDelete(llvm::function_ref<bool(unsigned)> isRedundantRuleFn) {
520535 }
521536
522537 for (const auto &pair : redundancyCandidates) {
538+ unsigned loopID = pair.first ;
523539 unsigned ruleID = pair.second ;
540+
541+ const auto &loop = Loops[loopID];
524542 const auto &rule = getRule (ruleID);
525543
526544 // We should not find a rule that has already been marked redundant
@@ -538,18 +556,18 @@ findRuleToDelete(llvm::function_ref<bool(unsigned)> isRedundantRuleFn) {
538556 // Homotopy reduction runs multiple passes with different filters to
539557 // prioritize the deletion of certain rules ahead of others. Apply
540558 // the filter now.
541- if (!isRedundantRuleFn (ruleID)) {
559+ if (!isRedundantRuleFn (loopID, ruleID)) {
542560 if (Debug.contains (DebugFlags::HomotopyReductionDetail)) {
543561 llvm::dbgs () << " ** Skipping rule " << rule << " from loop #"
544- << pair. first << " \n " ;
562+ << loopID << " \n " ;
545563 }
546564
547565 continue ;
548566 }
549567
550568 if (Debug.contains (DebugFlags::HomotopyReductionDetail)) {
551569 llvm::dbgs () << " ** Candidate rule " << rule << " from loop #"
552- << pair. first << " \n " ;
570+ << loopID << " \n " ;
553571 }
554572
555573 if (!found) {
@@ -561,7 +579,6 @@ findRuleToDelete(llvm::function_ref<bool(unsigned)> isRedundantRuleFn) {
561579 // we've found so far.
562580 const auto &otherRule = getRule (found->second );
563581
564- const auto &loop = Loops[pair.first ];
565582 const auto &otherLoop = Loops[found->first ];
566583
567584 {
@@ -712,7 +729,7 @@ void RewriteSystem::deleteRule(unsigned ruleID,
712729}
713730
714731void RewriteSystem::performHomotopyReduction (
715- llvm::function_ref< bool ( unsigned )> isRedundantRuleFn) {
732+ EliminationPredicate isRedundantRuleFn) {
716733 while (true ) {
717734 auto optPair = findRuleToDelete (isRedundantRuleFn);
718735
@@ -803,14 +820,21 @@ void RewriteSystem::minimizeRewriteSystem() {
803820 // First pass:
804821 // - Eliminate all LHS-simplified non-conformance rules.
805822 // - Eliminate all RHS-simplified and substitution-simplified rules.
806- // - Eliminate all rules with unresolved symbols.
823+ //
824+ // An example of a conformance rule that is LHS-simplified but not
825+ // RHS-simplified is (T.[P] => T) where T is irreducible, but there
826+ // is a rule (V.[P] => V) for some V with T == U.V.
827+ //
828+ // Such conformance rules can still be minimal, as part of a hack to
829+ // maintain compatibility with the GenericSignatureBuilder's minimization
830+ // algorithm.
807831 if (Debug.contains (DebugFlags::HomotopyReduction)) {
808- llvm::dbgs () << " --------------------------------------------- \n " ;
809- llvm::dbgs () << " First pass: simplified and unresolved rules -\n " ;
810- llvm::dbgs () << " --------------------------------------------- \n " ;
832+ llvm::dbgs () << " ------------------------------\n " ;
833+ llvm::dbgs () << " First pass: simplified rules -\n " ;
834+ llvm::dbgs () << " ------------------------------\n " ;
811835 }
812836
813- performHomotopyReduction ([&](unsigned ruleID) -> bool {
837+ performHomotopyReduction ([&](unsigned loopID, unsigned ruleID) -> bool {
814838 const auto &rule = getRule (ruleID);
815839
816840 if (rule.isLHSSimplified () &&
@@ -821,8 +845,31 @@ void RewriteSystem::minimizeRewriteSystem() {
821845 rule.isSubstitutionSimplified ())
822846 return true ;
823847
824- if (rule.containsUnresolvedSymbols () &&
825- !rule.isProtocolTypeAliasRule ())
848+ return false ;
849+ });
850+
851+ // Second pass:
852+ // - Eliminate all rules with unresolved symbols which were *not*
853+ // simplified.
854+ //
855+ // Two examples of such rules:
856+ //
857+ // - (T.X => T.[P:X]) obtained from resolving the overlap between
858+ // (T.[P] => T) and ([P].X => [P:X]).
859+ //
860+ // - (T.X.[concrete: C] => T.X) obtained from resolving the overlap
861+ // between (T.[P] => T) and a protocol typealias rule
862+ // ([P].X.[concrete: C] => [P].X).
863+ if (Debug.contains (DebugFlags::HomotopyReduction)) {
864+ llvm::dbgs () << " -------------------------------\n " ;
865+ llvm::dbgs () << " Second pass: unresolved rules -\n " ;
866+ llvm::dbgs () << " -------------------------------\n " ;
867+ }
868+
869+ performHomotopyReduction ([&](unsigned loopID, unsigned ruleID) -> bool {
870+ const auto &rule = getRule (ruleID);
871+
872+ if (rule.containsUnresolvedSymbols ())
826873 return true ;
827874
828875 return false ;
@@ -838,14 +885,14 @@ void RewriteSystem::minimizeRewriteSystem() {
838885 llvm::DenseSet<unsigned > redundantConformances;
839886 computeMinimalConformances (redundantConformances);
840887
841- // Second pass: Eliminate all non-minimal conformance rules.
888+ // Third pass: Eliminate all non-minimal conformance rules.
842889 if (Debug.contains (DebugFlags::HomotopyReduction)) {
843- llvm::dbgs () << " -------------------------------------------- \n " ;
844- llvm::dbgs () << " Second pass: non-minimal conformance rules -\n " ;
845- llvm::dbgs () << " -------------------------------------------- \n " ;
890+ llvm::dbgs () << " -------------------------------------------\n " ;
891+ llvm::dbgs () << " Third pass: non-minimal conformance rules -\n " ;
892+ llvm::dbgs () << " -------------------------------------------\n " ;
846893 }
847894
848- performHomotopyReduction ([&](unsigned ruleID) -> bool {
895+ performHomotopyReduction ([&](unsigned loopID, unsigned ruleID) -> bool {
849896 const auto &rule = getRule (ruleID);
850897
851898 if (rule.isAnyConformanceRule () &&
@@ -855,17 +902,22 @@ void RewriteSystem::minimizeRewriteSystem() {
855902 return false ;
856903 });
857904
858- // Third pass: Eliminate all other redundant non-conformance rules.
905+ // Fourth pass: Eliminate all remaining redundant non-conformance rules.
859906 if (Debug.contains (DebugFlags::HomotopyReduction)) {
860- llvm::dbgs () << " ---------------------------------------\n " ;
861- llvm::dbgs () << " Third pass: all other redundant rules -\n " ;
862- llvm::dbgs () << " ---------------------------------------\n " ;
907+ llvm::dbgs () << " ---------------------------------------- \n " ;
908+ llvm::dbgs () << " Fourth pass: all other redundant rules -\n " ;
909+ llvm::dbgs () << " ---------------------------------------- \n " ;
863910 }
864911
865- performHomotopyReduction ([&](unsigned ruleID) -> bool {
912+ performHomotopyReduction ([&](unsigned loopID, unsigned ruleID) -> bool {
913+ const auto &loop = Loops[loopID];
866914 const auto &rule = getRule (ruleID);
867915
868- if (!rule.isAnyConformanceRule ())
916+ if (rule.isProtocolTypeAliasRule ())
917+ return true ;
918+
919+ if (!loop.hasConcreteTypeAliasRule (*this ) &&
920+ !rule.isAnyConformanceRule ())
869921 return true ;
870922
871923 return false ;
0 commit comments