@@ -192,9 +192,22 @@ class MinimalConformances {
192
192
MutableTerm term, unsigned ruleID,
193
193
SmallVectorImpl<unsigned > &result) const ;
194
194
195
+ enum class ConcreteConformances : uint8_t {
196
+ // / Don't consider paths involving concrete conformances at all.
197
+ Disallowed,
198
+
199
+ // / Consider paths involving a concrete conformance only if it appears
200
+ // / at the end of the path.
201
+ AllowedAtEnd,
202
+
203
+ // / Consider paths involving concrete conformances anywhere.
204
+ AllowedAnywhere
205
+ };
206
+
195
207
bool isValidConformancePath (
196
208
llvm::SmallDenseSet<unsigned , 4 > &visited,
197
- const llvm::SmallVectorImpl<unsigned > &path, bool allowConcrete) const ;
209
+ const llvm::SmallVectorImpl<unsigned > &path,
210
+ ConcreteConformances allowConcrete) const ;
198
211
199
212
bool isValidRefinementPath (
200
213
const llvm::SmallVectorImpl<unsigned > &path) const ;
@@ -619,7 +632,8 @@ void MinimalConformances::computeCandidateConformancePaths() {
619
632
// / rules.
620
633
bool MinimalConformances::isValidConformancePath (
621
634
llvm::SmallDenseSet<unsigned , 4 > &visited,
622
- const llvm::SmallVectorImpl<unsigned > &path, bool allowConcrete) const {
635
+ const llvm::SmallVectorImpl<unsigned > &path,
636
+ ConcreteConformances allowConcrete) const {
623
637
624
638
unsigned lastIdx = path.size () - 1 ;
625
639
@@ -628,13 +642,27 @@ bool MinimalConformances::isValidConformancePath(
628
642
if (visited.count (ruleID) > 0 )
629
643
return false ;
630
644
645
+ const auto &rule = System.getRule (ruleID);
646
+
631
647
bool isLastElement = (ruleIdx == lastIdx);
648
+ bool isConcreteConformance = rule.getLHS ().back ().getKind ()
649
+ == Symbol::Kind::ConcreteConformance;
632
650
633
651
// Concrete conformances cannot appear in the middle of a conformance path.
634
- if (!allowConcrete || !isLastElement ) {
635
- if (System. getRule (ruleID). getLHS (). back (). getKind ()
636
- == Symbol::Kind::ConcreteConformance)
652
+ if (isConcreteConformance ) {
653
+ switch (allowConcrete) {
654
+ case ConcreteConformances::Disallowed:
637
655
return false ;
656
+
657
+ case ConcreteConformances::AllowedAtEnd:
658
+ if (!isLastElement)
659
+ return false ;
660
+
661
+ break ;
662
+
663
+ case ConcreteConformances::AllowedAnywhere:
664
+ break ;
665
+ }
638
666
}
639
667
640
668
if (RedundantConformances.count (ruleID)) {
@@ -647,10 +675,29 @@ bool MinimalConformances::isValidConformancePath(
647
675
if (found == ConformancePaths.end ())
648
676
return false ;
649
677
678
+ ConcreteConformances allowConcreteRec;
679
+ switch (allowConcrete) {
680
+ case ConcreteConformances::Disallowed:
681
+ allowConcreteRec = ConcreteConformances::Disallowed;
682
+ break ;
683
+
684
+ case ConcreteConformances::AllowedAnywhere:
685
+ allowConcreteRec = ConcreteConformances::AllowedAnywhere;
686
+ break ;
687
+
688
+ case ConcreteConformances::AllowedAtEnd:
689
+ if (isLastElement)
690
+ allowConcreteRec = ConcreteConformances::AllowedAtEnd;
691
+ else
692
+ allowConcreteRec = ConcreteConformances::Disallowed;
693
+
694
+ break ;
695
+ }
696
+
650
697
bool foundValidConformancePath = false ;
651
698
for (const auto &otherPath : found->second ) {
652
699
if (isValidConformancePath (visited, otherPath,
653
- allowConcrete && isLastElement )) {
700
+ allowConcreteRec )) {
654
701
foundValidConformancePath = true ;
655
702
break ;
656
703
}
@@ -666,11 +713,17 @@ bool MinimalConformances::isValidConformancePath(
666
713
};
667
714
visited.insert (ruleID);
668
715
716
+ ConcreteConformances allowConcreteRec;
717
+ if (isConcreteConformance)
718
+ allowConcreteRec = ConcreteConformances::AllowedAnywhere;
719
+ else
720
+ allowConcreteRec = ConcreteConformances::AllowedAtEnd;
721
+
669
722
// If 'req' is based on some other conformance requirement
670
723
// `T.[P.]A : Q', we want to make sure that we have a
671
724
// non-redundant derivation for 'T : P'.
672
725
if (!isValidConformancePath (visited, found->second ,
673
- /* allowConcrete= */ false )) {
726
+ allowConcreteRec )) {
674
727
return false ;
675
728
}
676
729
}
@@ -868,7 +921,7 @@ void MinimalConformances::computeMinimalConformances(bool firstPass) {
868
921
visited.insert (ruleID);
869
922
870
923
if (isValidConformancePath (visited, path,
871
- /* allowConcrete= */ true )) {
924
+ ConcreteConformances::AllowedAtEnd )) {
872
925
if (Debug.contains (DebugFlags::MinimalConformances)) {
873
926
llvm::dbgs () << " Redundant rule in " ;
874
927
llvm::dbgs () << (firstPass ? " first" : " second" );
@@ -902,8 +955,19 @@ void MinimalConformances::verifyMinimalConformances() const {
902
955
llvm::SmallVector<unsigned , 1 > path;
903
956
path.push_back (ruleID);
904
957
905
- if (!isValidConformancePath (visited, path,
906
- /* allowConcrete=*/ true )) {
958
+ ConcreteConformances allowConcrete;
959
+ if (rule.isProtocolConformanceRule ()) {
960
+ // Protocol conformance rules are recoverable if the path
961
+ // has a concrete conformance at the end.
962
+ allowConcrete = ConcreteConformances::AllowedAtEnd;
963
+ } else {
964
+ // Concrete conformance rules are recoverable via paths
965
+ // containing other concrete conformances anywhere.
966
+ assert (rule.isAnyConformanceRule ());
967
+ allowConcrete = ConcreteConformances::AllowedAnywhere;
968
+ }
969
+
970
+ if (!isValidConformancePath (visited, path, allowConcrete)) {
907
971
llvm::errs () << " Redundant conformance is not recoverable:\n " ;
908
972
llvm::errs () << rule << " \n\n " ;
909
973
dumpMinimalConformanceEquations (llvm::errs ());
0 commit comments