65
65
using namespace swift ;
66
66
using namespace rewriting ;
67
67
68
- // / Recompute Useful, RulesInEmptyContext, ProjectionCount and DecomposeCount
69
- // / if needed.
68
+ // / Recompute various cached values if needed.
70
69
void RewriteLoop::recompute (const RewriteSystem &system) {
71
70
if (!Dirty)
72
71
return ;
73
72
Dirty = 0 ;
74
73
74
+ Useful = 0 ;
75
75
ProjectionCount = 0 ;
76
76
DecomposeCount = 0 ;
77
- Useful = false ;
77
+ HasConcreteTypeAliasRule = 0 ;
78
78
79
79
RewritePathEvaluator evaluator (Basepoint);
80
80
for (auto step : Path) {
81
81
switch (step.Kind ) {
82
- case RewriteStep::Rule:
82
+ case RewriteStep::Rule: {
83
83
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
+
84
90
break ;
91
+ }
85
92
86
93
case RewriteStep::LeftConcreteProjection:
87
94
++ProjectionCount;
@@ -130,6 +137,14 @@ unsigned RewriteLoop::getDecomposeCount(
130
137
return DecomposeCount;
131
138
}
132
139
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
+
133
148
// / The number of Decompose steps, used by the elimination order to prioritize
134
149
// / loops that are not concrete simplifications.
135
150
bool RewriteLoop::isUseful (
@@ -488,7 +503,7 @@ RewritePath::getRulesInEmptyContext(const MutableTerm &term,
488
503
// / \p redundantConformances equal to the set of conformance rules that are
489
504
// / not minimal conformances.
490
505
Optional<std::pair<unsigned , unsigned >> RewriteSystem::
491
- findRuleToDelete (llvm::function_ref< bool ( unsigned )> isRedundantRuleFn) {
506
+ findRuleToDelete (EliminationPredicate isRedundantRuleFn) {
492
507
SmallVector<std::pair<unsigned , unsigned >, 2 > redundancyCandidates;
493
508
for (unsigned loopID : indices (Loops)) {
494
509
auto &loop = Loops[loopID];
@@ -520,7 +535,10 @@ findRuleToDelete(llvm::function_ref<bool(unsigned)> isRedundantRuleFn) {
520
535
}
521
536
522
537
for (const auto &pair : redundancyCandidates) {
538
+ unsigned loopID = pair.first ;
523
539
unsigned ruleID = pair.second ;
540
+
541
+ const auto &loop = Loops[loopID];
524
542
const auto &rule = getRule (ruleID);
525
543
526
544
// We should not find a rule that has already been marked redundant
@@ -538,18 +556,18 @@ findRuleToDelete(llvm::function_ref<bool(unsigned)> isRedundantRuleFn) {
538
556
// Homotopy reduction runs multiple passes with different filters to
539
557
// prioritize the deletion of certain rules ahead of others. Apply
540
558
// the filter now.
541
- if (!isRedundantRuleFn (ruleID)) {
559
+ if (!isRedundantRuleFn (loopID, ruleID)) {
542
560
if (Debug.contains (DebugFlags::HomotopyReductionDetail)) {
543
561
llvm::dbgs () << " ** Skipping rule " << rule << " from loop #"
544
- << pair. first << " \n " ;
562
+ << loopID << " \n " ;
545
563
}
546
564
547
565
continue ;
548
566
}
549
567
550
568
if (Debug.contains (DebugFlags::HomotopyReductionDetail)) {
551
569
llvm::dbgs () << " ** Candidate rule " << rule << " from loop #"
552
- << pair. first << " \n " ;
570
+ << loopID << " \n " ;
553
571
}
554
572
555
573
if (!found) {
@@ -561,7 +579,6 @@ findRuleToDelete(llvm::function_ref<bool(unsigned)> isRedundantRuleFn) {
561
579
// we've found so far.
562
580
const auto &otherRule = getRule (found->second );
563
581
564
- const auto &loop = Loops[pair.first ];
565
582
const auto &otherLoop = Loops[found->first ];
566
583
567
584
{
@@ -712,7 +729,7 @@ void RewriteSystem::deleteRule(unsigned ruleID,
712
729
}
713
730
714
731
void RewriteSystem::performHomotopyReduction (
715
- llvm::function_ref< bool ( unsigned )> isRedundantRuleFn) {
732
+ EliminationPredicate isRedundantRuleFn) {
716
733
while (true ) {
717
734
auto optPair = findRuleToDelete (isRedundantRuleFn);
718
735
@@ -803,14 +820,21 @@ void RewriteSystem::minimizeRewriteSystem() {
803
820
// First pass:
804
821
// - Eliminate all LHS-simplified non-conformance rules.
805
822
// - 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.
807
831
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 " ;
811
835
}
812
836
813
- performHomotopyReduction ([&](unsigned ruleID) -> bool {
837
+ performHomotopyReduction ([&](unsigned loopID, unsigned ruleID) -> bool {
814
838
const auto &rule = getRule (ruleID);
815
839
816
840
if (rule.isLHSSimplified () &&
@@ -821,8 +845,31 @@ void RewriteSystem::minimizeRewriteSystem() {
821
845
rule.isSubstitutionSimplified ())
822
846
return true ;
823
847
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 ())
826
873
return true ;
827
874
828
875
return false ;
@@ -838,14 +885,14 @@ void RewriteSystem::minimizeRewriteSystem() {
838
885
llvm::DenseSet<unsigned > redundantConformances;
839
886
computeMinimalConformances (redundantConformances);
840
887
841
- // Second pass: Eliminate all non-minimal conformance rules.
888
+ // Third pass: Eliminate all non-minimal conformance rules.
842
889
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 " ;
846
893
}
847
894
848
- performHomotopyReduction ([&](unsigned ruleID) -> bool {
895
+ performHomotopyReduction ([&](unsigned loopID, unsigned ruleID) -> bool {
849
896
const auto &rule = getRule (ruleID);
850
897
851
898
if (rule.isAnyConformanceRule () &&
@@ -855,17 +902,22 @@ void RewriteSystem::minimizeRewriteSystem() {
855
902
return false ;
856
903
});
857
904
858
- // Third pass: Eliminate all other redundant non-conformance rules.
905
+ // Fourth pass: Eliminate all remaining redundant non-conformance rules.
859
906
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 " ;
863
910
}
864
911
865
- performHomotopyReduction ([&](unsigned ruleID) -> bool {
912
+ performHomotopyReduction ([&](unsigned loopID, unsigned ruleID) -> bool {
913
+ const auto &loop = Loops[loopID];
866
914
const auto &rule = getRule (ruleID);
867
915
868
- if (!rule.isAnyConformanceRule ())
916
+ if (rule.isProtocolTypeAliasRule ())
917
+ return true ;
918
+
919
+ if (!loop.hasConcreteTypeAliasRule (*this ) &&
920
+ !rule.isAnyConformanceRule ())
869
921
return true ;
870
922
871
923
return false ;
0 commit comments