Skip to content

Commit dbb5343

Browse files
committed
[Constraint graph] Generalize the implementation of depth-first search.
(cherry picked from commit 6737cf9)
1 parent a51795f commit dbb5343

File tree

1 file changed

+76
-28
lines changed

1 file changed

+76
-28
lines changed

lib/Sema/ConstraintGraph.cpp

Lines changed: 76 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -536,22 +536,31 @@ void ConstraintGraph::gatherConstraints(
536536

537537
#pragma mark Algorithms
538538

539-
/// Depth-first search for connected components
540-
static void connectedComponentsDFS(
539+
/// Perform a depth-first search.
540+
///
541+
/// \param cg The constraint graph.
542+
/// \param node The current constraint graph node.
543+
/// \param nodeIndex The index of the current constraint graph node.
544+
/// \param visitFixedBindings Whether to visit the nodes by following
545+
/// fixed bindings.
546+
/// \param preVisitNode Called before traversing a node. Must return \c
547+
/// false when the node has already been visited.
548+
/// \param visitConstraint Called before considering a constraint. If it
549+
/// returns \c false, that constraint will be skipped.
550+
/// \param visitedConstraints Set of already-visited constraints, used
551+
/// internally to avoid duplicated work.
552+
static void depthFirstSearch(
541553
ConstraintGraph &cg,
542554
ConstraintGraphNode &node,
543555
unsigned nodeIndex,
544-
unsigned component,
545-
std::vector<unsigned> &components,
556+
bool visitFixedBindings,
557+
llvm::function_ref<bool(unsigned)> preVisitNode,
558+
llvm::function_ref<bool(Constraint *)> visitConstraint,
546559
llvm::DenseSet<Constraint *> &visitedConstraints) {
547-
// If we have already seen this node, we're done.
548-
unsigned &nodeComponent = components[nodeIndex];
549-
if (nodeComponent == component)
560+
// Visit this node. If we've already seen it, bail out.
561+
if (!preVisitNode(nodeIndex))
550562
return;
551563

552-
assert(nodeComponent == components.size() && "Already in a component?");
553-
nodeComponent = component;
554-
555564
// Local function to visit adjacent type variables.
556565
auto visitAdjacencies = [&](ArrayRef<TypeVariableType *> adjTypeVars) {
557566
for (auto adj : adjTypeVars) {
@@ -560,9 +569,10 @@ static void connectedComponentsDFS(
560569

561570
auto adjNodeAndIndex = cg.lookupNode(adj);
562571

563-
// Visit the next node.
564-
connectedComponentsDFS(cg, adjNodeAndIndex.first, adjNodeAndIndex.second,
565-
component, components, visitedConstraints);
572+
// Recurse into this node.
573+
depthFirstSearch(cg, adjNodeAndIndex.first, adjNodeAndIndex.second,
574+
visitFixedBindings, preVisitNode, visitConstraint,
575+
visitedConstraints);
566576
}
567577
};
568578

@@ -573,26 +583,49 @@ static void connectedComponentsDFS(
573583
if (!visitedConstraints.insert(constraint).second)
574584
continue;
575585

576-
visitAdjacencies(constraint->getTypeVariables());
586+
if (visitConstraint(constraint))
587+
visitAdjacencies(constraint->getTypeVariables());
577588
}
578589

579-
// Walk any type variables related via fixed bindings.
580-
visitAdjacencies(node.getFixedAdjacencies());
581-
582590
// Visit all of the other nodes in the equivalence class.
583591
auto nodeTypeVar = node.getTypeVariable();
584592
auto repTypeVar = cg.getConstraintSystem().getRepresentative(nodeTypeVar);
585-
if (nodeTypeVar != repTypeVar) {
586-
// We are not the representative; visit the representative to be sure.
587-
auto repNodeAndIndex = cg.lookupNode(repTypeVar);
588-
connectedComponentsDFS(cg, repNodeAndIndex.first, repNodeAndIndex.second,
589-
component, components, visitedConstraints);
590-
return;
593+
if (nodeTypeVar == repTypeVar) {
594+
// We are the representative, so visit all of the other type variables
595+
// in this equivalence class.
596+
visitAdjacencies(node.getEquivalenceClass());
597+
} else {
598+
// We are not the representative; visit the representative.
599+
visitAdjacencies(repTypeVar);
600+
}
601+
602+
if (visitFixedBindings) {
603+
// Walk any type variables related via fixed bindings.
604+
visitAdjacencies(node.getFixedAdjacencies());
591605
}
606+
}
592607

593-
// We are the representative, so visit all of the other type variables
594-
// in this equivalence class.
595-
visitAdjacencies(node.getEquivalenceClass());
608+
/// Perform a depth-first search.
609+
///
610+
/// \param cg The constraint graph.
611+
/// \param node The current constraint graph node.
612+
/// \param nodeIndex The index of the current constraint graph node.
613+
/// \param visitFixedBindings Whether to visit the nodes by following
614+
/// fixed bindings.
615+
/// \param preVisitNode Called before traversing a node. Must return \c
616+
/// false when the node has already been visited.
617+
/// \param visitConstraint Called before considering a constraint. If it
618+
/// returns \c false, that constraint will be skipped.
619+
static void depthFirstSearch(
620+
ConstraintGraph &cg,
621+
ConstraintGraphNode &node,
622+
unsigned nodeIndex,
623+
bool visitFixedBindings,
624+
llvm::function_ref<bool(unsigned)> preVisitNode,
625+
llvm::function_ref<bool(Constraint *)> visitConstraint) {
626+
llvm::DenseSet<Constraint *> visitedConstraints;
627+
depthFirstSearch(cg, node, nodeIndex, visitFixedBindings, preVisitNode,
628+
visitConstraint, visitedConstraints);
596629
}
597630

598631
unsigned ConstraintGraph::computeConnectedComponents(
@@ -628,8 +661,23 @@ unsigned ConstraintGraph::computeConnectedComponents(
628661
unsigned component = numComponents++;
629662

630663
// Note that this node is part of this component, then visit it.
631-
connectedComponentsDFS(*this, nodeAndIndex.first, nodeAndIndex.second,
632-
component, components, visitedConstraints);
664+
depthFirstSearch(
665+
*this, nodeAndIndex.first, nodeAndIndex.second,
666+
/*visitFixedBindings=*/true,
667+
[&](unsigned nodeIndex) {
668+
// If we have already seen this node, we're done.
669+
unsigned &nodeComponent = components[nodeIndex];
670+
if (nodeComponent == component)
671+
return false;
672+
673+
assert(nodeComponent == components.size() &&
674+
"Already in a component?");
675+
nodeComponent = component;
676+
return true;
677+
},
678+
[&](Constraint *constraint) {
679+
return true;
680+
});
633681
}
634682

635683
// Figure out which components have unbound type variables; these

0 commit comments

Comments
 (0)