Skip to content

Commit c629e03

Browse files
committed
---
yaml --- r: 315382 b: refs/heads/master-next c: 73e5a64 h: refs/heads/master
1 parent 298db2c commit c629e03

File tree

3 files changed

+116
-24
lines changed

3 files changed

+116
-24
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
refs/heads/master: 3fe9333052029c114ef816ea805c335eb1ee8a99
3-
refs/heads/master-next: f19016b94b0f0b8ed2fff8c0d3316504402bc21c
3+
refs/heads/master-next: 73e5a64bd1f3c4a86024a34f062b5dd6c83a3f11
44
refs/tags/osx-passed: b6b74147ef8a386f532cf9357a1bde006e552c54
55
refs/tags/swift-2.2-SNAPSHOT-2015-12-01-a: 6bb18e013c2284f2b45f5f84f2df2887dc0f7dea
66
refs/tags/swift-2.2-SNAPSHOT-2015-12-01-b: 66d897bfcf64a82cb9a87f5e663d889189d06d07

branches/master-next/include/swift/Basic/Statistics.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,11 @@ FRONTEND_STATISTIC(Sema, NumLeafScopes)
166166
/// This is a measure of complexity of the contraction algorithm.
167167
FRONTEND_STATISTIC(Sema, NumConstraintsConsideredForEdgeContraction)
168168

169+
/// Number of constraint-solving scopes created in the typechecker, while
170+
/// solving expression type constraints. A rough proxy for "how much work the
171+
/// expression typechecker did".
172+
FRONTEND_STATISTIC(Sema, NumCyclicOneWayComponentsCollapsed)
173+
169174
/// Number of declarations that were deserialized. A rough proxy for the amount
170175
/// of material loaded from other modules.
171176
FRONTEND_STATISTIC(Sema, NumDeclsDeserialized)

branches/master-next/lib/Sema/ConstraintGraph.cpp

Lines changed: 110 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,26 @@ namespace {
723723
}
724724

725725
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+
726746
/// Perform the connected components algorithm, skipping one-way
727747
/// constraints.
728748
///
@@ -773,24 +793,24 @@ namespace {
773793
vector.push_back(typeVar);
774794
}
775795

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;
789801

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+
}
792811

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) {
794814
for (auto constraint : oneWayConstraints) {
795815
auto lhsTypeReps =
796816
getRepresentativesInType(constraint->getFirstType());
@@ -803,14 +823,56 @@ namespace {
803823
// be solved before the left-hand type variables.
804824
for (auto lhsTypeRep : lhsTypeReps) {
805825
for (auto rhsTypeRep : rhsTypeReps) {
826+
if (lhsTypeRep == rhsTypeRep)
827+
break;
828+
806829
insertIfUnique(oneWayDigraph[rhsTypeRep].outAdjacencies,lhsTypeRep);
807830
insertIfUnique(oneWayDigraph[lhsTypeRep].inAdjacencies,rhsTypeRep);
808831
}
809832
}
810833
}
834+
}
835+
836+
using TypeVariablePair = std::pair<TypeVariableType *, TypeVariableType *>;
811837

812-
// Minimize the in-adjacencies.
813-
removeIndirectOneWayInAdjacencies();
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+
}
871+
872+
contractedCycle = true;
873+
}
874+
}
875+
} while (contractedCycle);
814876
}
815877

816878
/// Perform a depth-first search to produce a from the given type variable,
@@ -845,14 +907,17 @@ namespace {
845907
/// Minimize the incoming adjacencies for one of the nodes in the one-way
846908
/// directed graph by eliminating any in-adjacencies that can also be
847909
/// found indirectly.
848-
void removeIndirectOneWayInAdjacencies(TypeVariableType *typeVar,
849-
OneWayComponent &component) {
910+
void removeIndirectOneWayInAdjacencies(
911+
TypeVariableType *typeVar,
912+
OneWayComponent &component,
913+
SmallVectorImpl<TypeVariablePair> &cycleEdges) {
850914
// Perform a depth-first search from each of the in adjacencies to
851915
// this type variable, traversing each of the one-way edges backwards
852916
// to find all of the components whose type variables must be
853917
// bound before this component can be solved.
854918
SmallPtrSet<TypeVariableType *, 4> visited;
855919
SmallPtrSet<TypeVariableType *, 4> indirectlyReachable;
920+
SmallVector<TypeVariableType *, 4> currentPath;
856921
for (auto inAdj : component.inAdjacencies) {
857922
postorderDepthFirstSearchRec(
858923
inAdj,
@@ -866,9 +931,30 @@ namespace {
866931
return oneWayComponent->second.inAdjacencies;
867932
},
868933
[&](TypeVariableType *typeVar) {
869-
return visited.insert(typeVar).second;
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;
870952
},
871953
[&](TypeVariableType *dependsOn) {
954+
// Remove this type variable from the path.
955+
assert(currentPath.back() == dependsOn);
956+
currentPath.pop_back();
957+
872958
// Don't record dependency on ourselves.
873959
if (dependsOn == inAdj)
874960
return;
@@ -891,11 +977,12 @@ namespace {
891977
/// Minimize the incoming adjacencies for all of the nodes in the one-way
892978
/// directed graph by eliminating any in-adjacencies that can also be
893979
/// found indirectly.
894-
void removeIndirectOneWayInAdjacencies() {
980+
void removeIndirectOneWayInAdjacencies(
981+
SmallVectorImpl<TypeVariablePair> &cycleEdges) {
895982
for (auto &oneWayEntry : oneWayDigraph) {
896983
auto typeVar = oneWayEntry.first;
897984
auto &component = oneWayEntry.second;
898-
removeIndirectOneWayInAdjacencies(typeVar, component);
985+
removeIndirectOneWayInAdjacencies(typeVar, component, cycleEdges);
899986
}
900987
}
901988

0 commit comments

Comments
 (0)