@@ -607,6 +607,9 @@ static const ProtocolDecl *getParentConformanceForTerm(Term lhs) {
607
607
// / conformance rules.
608
608
void RewriteSystem::computeGeneratingConformances (
609
609
llvm::DenseSet<unsigned > &redundantConformances) {
610
+ // All conformance rules, sorted by left hand side.
611
+ SmallVector<std::pair<unsigned , Term>, 4 > conformanceRules;
612
+
610
613
// Maps a conformance rule to a conformance path deriving the subject type's
611
614
// base type. For example, consider the following conformance rule:
612
615
//
@@ -625,8 +628,7 @@ void RewriteSystem::computeGeneratingConformances(
625
628
// the form [P].[Q] => [P].
626
629
llvm::DenseSet<unsigned > protocolRefinements;
627
630
628
- // Prepare the initial set of equations: every non-redundant conformance rule
629
- // can be expressed as itself.
631
+ // Prepare the initial set of equations.
630
632
for (unsigned ruleID : indices (Rules)) {
631
633
const auto &rule = getRule (ruleID);
632
634
if (rule.isPermanent ())
@@ -638,17 +640,21 @@ void RewriteSystem::computeGeneratingConformances(
638
640
if (!rule.isProtocolConformanceRule ())
639
641
continue ;
640
642
643
+ auto lhs = rule.getLHS ();
644
+ conformanceRules.emplace_back (ruleID, lhs);
645
+
646
+ // Initially, every non-redundant conformance rule can be expressed
647
+ // as itself.
641
648
SmallVector<unsigned , 2 > path;
642
649
path.push_back (ruleID);
643
650
conformancePaths[ruleID].push_back (path);
644
651
652
+ // Save protocol refinement relations in a side table.
645
653
if (rule.isProtocolRefinementRule ()) {
646
654
protocolRefinements.insert (ruleID);
647
655
continue ;
648
656
}
649
657
650
- auto lhs = rule.getLHS ();
651
-
652
658
// Record a parent path if the subject type itself requires a non-trivial
653
659
// conformance path to derive.
654
660
if (auto *parentProto = getParentConformanceForTerm (lhs)) {
@@ -687,22 +693,33 @@ void RewriteSystem::computeGeneratingConformances(
687
693
688
694
verifyGeneratingConformanceEquations (conformancePaths);
689
695
696
+ // Sort the list of conformance rules in reverse order; we're going to try
697
+ // to minimize away less canonical rules first.
698
+ std::sort (conformanceRules.begin (), conformanceRules.end (),
699
+ [&](const std::pair<unsigned , Term> &lhs,
700
+ const std::pair<unsigned , Term> &rhs) -> bool {
701
+ return lhs.second .compare (rhs.second , Context) > 0 ;
702
+ });
703
+
690
704
// Find a minimal set of generating conformances.
691
- for (const auto &pair : conformancePaths) {
692
- bool isProtocolRefinement = protocolRefinements.count (pair.first ) > 0 ;
705
+ for (const auto &pair : conformanceRules) {
706
+ unsigned ruleID = pair.first ;
707
+ const auto &paths = conformancePaths[ruleID];
693
708
694
- for (const auto &path : pair.second ) {
709
+ bool isProtocolRefinement = protocolRefinements.count (ruleID) > 0 ;
710
+
711
+ for (const auto &path : paths) {
695
712
// Only consider a protocol refinement rule to be redundant if it is
696
713
// witnessed by a composition of other protocol refinement rules.
697
714
if (isProtocolRefinement && !isValidRefinementPath (path))
698
715
continue ;
699
716
700
717
llvm::SmallDenseSet<unsigned , 4 > visited;
701
- visited.insert (pair. first );
718
+ visited.insert (ruleID );
702
719
703
720
if (isValidConformancePath (visited, redundantConformances, path,
704
721
parentPaths, conformancePaths)) {
705
- redundantConformances.insert (pair. first );
722
+ redundantConformances.insert (ruleID );
706
723
break ;
707
724
}
708
725
}
0 commit comments