@@ -723,6 +723,26 @@ namespace {
723
723
}
724
724
725
725
private:
726
+ // / Perform the union of two type variables in a union-find data structure
727
+ // / used for connected components.
728
+ // /
729
+ // / \returns true if the two components were separate and have now been
730
+ // / joined, \c false if they were already in the same set.
731
+ bool unionSets (TypeVariableType *typeVar1, TypeVariableType *typeVar2) {
732
+ auto rep1 = findRepresentative (typeVar1);
733
+ auto rep2 = findRepresentative (typeVar2);
734
+ if (rep1 == rep2)
735
+ return false ;
736
+
737
+ // Reparent the type variable with the higher ID. The actual choice doesn't
738
+ // matter, but this makes debugging easier.
739
+ if (rep1->getID () < rep2->getID ())
740
+ representatives[rep2] = rep1;
741
+ else
742
+ representatives[rep1] = rep2;
743
+ return true ;
744
+ }
745
+
726
746
// / Perform the connected components algorithm, skipping one-way
727
747
// / constraints.
728
748
// /
@@ -773,24 +793,24 @@ namespace {
773
793
vector.push_back (typeVar);
774
794
}
775
795
776
- // / Build the directed graph of one-way constraints among components.
777
- void buildOneWayConstraintGraph (ArrayRef<Constraint *> oneWayConstraints) {
778
- // / Retrieve the set of representatives for the type variables that
779
- // / occur within the given type.
780
- auto getRepresentativesInType = [&](Type type) {
781
- TinyPtrVector<TypeVariableType *> results;
782
-
783
- SmallVector<TypeVariableType *, 2 > typeVars;
784
- type->getTypeVariables (typeVars);
785
- for (auto typeVar : typeVars) {
786
- auto rep = findRepresentative (typeVar);
787
- insertIfUnique (results, rep);
788
- }
796
+ // / Retrieve the (uniqued) set of type variable representations that occur
797
+ // / within the given type.
798
+ TinyPtrVector<TypeVariableType *>
799
+ getRepresentativesInType (Type type) const {
800
+ TinyPtrVector<TypeVariableType *> results;
789
801
790
- return results;
791
- };
802
+ SmallVector<TypeVariableType *, 2 > typeVars;
803
+ type->getTypeVariables (typeVars);
804
+ for (auto typeVar : typeVars) {
805
+ auto rep = findRepresentative (typeVar);
806
+ insertIfUnique (results, rep);
807
+ }
808
+
809
+ return results;
810
+ }
792
811
793
- // Add all of the one-way constraint edges to the digraph.
812
+ // / Add all of the one-way constraints to the one-way digraph
813
+ void addOneWayConstraintEdges (ArrayRef<Constraint *> oneWayConstraints) {
794
814
for (auto constraint : oneWayConstraints) {
795
815
auto lhsTypeReps =
796
816
getRepresentativesInType (constraint->getFirstType ());
@@ -803,30 +823,82 @@ namespace {
803
823
// be solved before the left-hand type variables.
804
824
for (auto lhsTypeRep : lhsTypeReps) {
805
825
for (auto rhsTypeRep : rhsTypeReps) {
826
+ if (lhsTypeRep == rhsTypeRep)
827
+ break ;
828
+
806
829
insertIfUnique (oneWayDigraph[rhsTypeRep].outAdjacencies ,lhsTypeRep);
807
830
insertIfUnique (oneWayDigraph[lhsTypeRep].inAdjacencies ,rhsTypeRep);
808
831
}
809
832
}
810
833
}
834
+ }
835
+
836
+ using TypeVariablePair = std::pair<TypeVariableType *, TypeVariableType *>;
837
+
838
+ // / Build the directed graph of one-way constraints among components.
839
+ void buildOneWayConstraintGraph (ArrayRef<Constraint *> oneWayConstraints) {
840
+ auto &cs = cg.getConstraintSystem ();
841
+ auto &ctx = cs.getASTContext ();
842
+ bool contractedCycle = false ;
843
+ do {
844
+ // Construct the one-way digraph from scratch.
845
+ oneWayDigraph.clear ();
846
+ addOneWayConstraintEdges (oneWayConstraints);
847
+
848
+ // Minimize the in-adjacencies, detecting cycles along the way.
849
+ SmallVector<TypeVariablePair, 4 > cycleEdges;
850
+ removeIndirectOneWayInAdjacencies (cycleEdges);
851
+
852
+ // For any contractions we need to perform due to cycles, perform a
853
+ // union the connected components based on the type variable pairs.
854
+ contractedCycle = false ;
855
+ for (const auto &edge : cycleEdges) {
856
+ if (unionSets (edge.first , edge.second )) {
857
+ if (ctx.LangOpts .DebugConstraintSolver ) {
858
+ auto &log = ctx.TypeCheckerDebug ->getStream ();
859
+ if (cs.solverState )
860
+ log.indent (cs.solverState ->depth * 2 );
861
+
862
+ log << " Collapsing one-way components for $T"
863
+ << edge.first ->getID () << " and $T" << edge.second ->getID ()
864
+ << " due to cycle.\n " ;
865
+ }
866
+
867
+ if (ctx.Stats ) {
868
+ ctx.Stats ->getFrontendCounters ()
869
+ .NumCyclicOneWayComponentsCollapsed ++;
870
+ }
811
871
812
- // Minimize the in-adjacencies.
813
- removeIndirectOneWayInAdjacencies ();
872
+ contractedCycle = true ;
873
+ }
874
+ }
875
+ } while (contractedCycle);
814
876
}
815
877
816
878
// / Perform a depth-first search to produce a from the given type variable,
817
- // / notifying the function object \c postVisit after each reachable
818
- // / type variable has been visited.
879
+ // / notifying the function object.
880
+ // /
881
+ // / \param getAdjacencies Called to retrieve the set of type variables
882
+ // / that are adjacent to the given type variable.
883
+ // /
884
+ // / \param preVisit Called before visiting the adjacencies of the given
885
+ // / type variable. When it returns \c true, the adjacencies of this type
886
+ // / variable will be visited. When \c false, the adjacencies will not be
887
+ // / visited and \c postVisit will not be called.
888
+ // /
889
+ // / \param postVisit Called after visiting the adjacencies of the given
890
+ // / type variable.
819
891
static void postorderDepthFirstSearchRec (
820
892
TypeVariableType *typeVar,
821
893
llvm::function_ref<
822
894
ArrayRef<TypeVariableType *>(TypeVariableType *)> getAdjacencies,
823
- llvm::function_ref<void (TypeVariableType *)> postVisit ,
824
- SmallPtrSet< TypeVariableType *, 4> &visited ) {
825
- if (!visited. insert (typeVar). second )
895
+ llvm::function_ref<bool (TypeVariableType *)> preVisit ,
896
+ llvm::function_ref<void( TypeVariableType *)> postVisit ) {
897
+ if (!preVisit (typeVar))
826
898
return ;
827
899
828
900
for (auto adj : getAdjacencies (typeVar)) {
829
- postorderDepthFirstSearchRec (adj, getAdjacencies, postVisit, visited );
901
+ postorderDepthFirstSearchRec (adj, getAdjacencies, preVisit, postVisit );
830
902
}
831
903
832
904
postVisit (typeVar);
@@ -835,14 +907,17 @@ namespace {
835
907
// / Minimize the incoming adjacencies for one of the nodes in the one-way
836
908
// / directed graph by eliminating any in-adjacencies that can also be
837
909
// / found indirectly.
838
- void removeIndirectOneWayInAdjacencies (TypeVariableType *typeVar,
839
- OneWayComponent &component) {
910
+ void removeIndirectOneWayInAdjacencies (
911
+ TypeVariableType *typeVar,
912
+ OneWayComponent &component,
913
+ SmallVectorImpl<TypeVariablePair> &cycleEdges) {
840
914
// Perform a depth-first search from each of the in adjacencies to
841
915
// this type variable, traversing each of the one-way edges backwards
842
916
// to find all of the components whose type variables must be
843
917
// bound before this component can be solved.
844
918
SmallPtrSet<TypeVariableType *, 4 > visited;
845
919
SmallPtrSet<TypeVariableType *, 4 > indirectlyReachable;
920
+ SmallVector<TypeVariableType *, 4 > currentPath;
846
921
for (auto inAdj : component.inAdjacencies ) {
847
922
postorderDepthFirstSearchRec (
848
923
inAdj,
@@ -855,14 +930,37 @@ namespace {
855
930
856
931
return oneWayComponent->second .inAdjacencies ;
857
932
},
933
+ [&](TypeVariableType *typeVar) {
934
+ // If we haven't seen this type variable yet, add it to the
935
+ // path.
936
+ if (visited.insert (typeVar).second ) {
937
+ currentPath.push_back (typeVar);
938
+ return true ;
939
+ }
940
+
941
+ // Add edges between this type variable and every other type
942
+ // variable in the path.
943
+ for (auto otherTypeVar : reversed (currentPath)) {
944
+ // When we run into our own type variable, we're done.
945
+ if (otherTypeVar == typeVar)
946
+ break ;
947
+
948
+ cycleEdges.push_back ({typeVar, otherTypeVar});
949
+ }
950
+
951
+ return false ;
952
+ },
858
953
[&](TypeVariableType *dependsOn) {
954
+ // Remove this type variable from the path.
955
+ assert (currentPath.back () == dependsOn);
956
+ currentPath.pop_back ();
957
+
859
958
// Don't record dependency on ourselves.
860
959
if (dependsOn == inAdj)
861
960
return ;
862
961
863
962
indirectlyReachable.insert (dependsOn);
864
- },
865
- visited);
963
+ });
866
964
867
965
// Remove any in-adjacency of this component that is indirectly
868
966
// reachable.
@@ -879,11 +977,12 @@ namespace {
879
977
// / Minimize the incoming adjacencies for all of the nodes in the one-way
880
978
// / directed graph by eliminating any in-adjacencies that can also be
881
979
// / found indirectly.
882
- void removeIndirectOneWayInAdjacencies () {
980
+ void removeIndirectOneWayInAdjacencies (
981
+ SmallVectorImpl<TypeVariablePair> &cycleEdges) {
883
982
for (auto &oneWayEntry : oneWayDigraph) {
884
983
auto typeVar = oneWayEntry.first ;
885
984
auto &component = oneWayEntry.second ;
886
- removeIndirectOneWayInAdjacencies (typeVar, component);
985
+ removeIndirectOneWayInAdjacencies (typeVar, component, cycleEdges );
887
986
}
888
987
}
889
988
@@ -922,13 +1021,15 @@ namespace {
922
1021
923
1022
return oneWayComponent->second .outAdjacencies ;
924
1023
},
1024
+ [&](TypeVariableType *typeVar) {
1025
+ return visited.insert (typeVar).second ;
1026
+ },
925
1027
[&](TypeVariableType *typeVar) {
926
1028
// Record this type variable, if it's one of the representative
927
1029
// type variables.
928
1030
if (validComponents.count (typeVar) > 0 )
929
1031
orderedReps.push_back (typeVar);
930
- },
931
- visited);
1032
+ });
932
1033
}
933
1034
934
1035
assert (orderedReps.size () == representativeTypeVars.size ());
@@ -1211,6 +1312,8 @@ void ConstraintGraph::printConnectedComponents(
1211
1312
}
1212
1313
1213
1314
void ConstraintGraph::dumpConnectedComponents () {
1315
+ llvm::SaveAndRestore<bool >
1316
+ debug (CS.getASTContext ().LangOpts .DebugConstraintSolver , true );
1214
1317
printConnectedComponents (CS.TypeVariables , llvm::dbgs ());
1215
1318
}
1216
1319
0 commit comments