Skip to content

Commit 1c5cba4

Browse files
committed
[Constraint graph] Make connected components more self-contained.
Have the constraint graph's connected-component implementation be more self-contained, producing a vector containing each of the actual components (where each is defined by a list of type variables and a list of constraints). This simplifies the contract with the client (SplitterStep) and eliminates a bunch of separate mapping steps to interpret the results. It also lets us enrich the Component data structure in the future. (cherry picked from commit 4c04ced)
1 parent 7ae3de2 commit 1c5cba4

File tree

5 files changed

+214
-178
lines changed

5 files changed

+214
-178
lines changed

lib/Sema/CSStep.cpp

Lines changed: 15 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -96,25 +96,31 @@ void SplitterStep::computeFollowupSteps(
9696
CG.optimize();
9797

9898
// Compute the connected components of the constraint graph.
99-
// FIXME: We're seeding typeVars with TypeVariables so that the
100-
// connected-components algorithm only considers those type variables within
101-
// our component. There are clearly better ways to do this.
102-
std::vector<TypeVariableType *> typeVars(CS.TypeVariables);
103-
std::vector<unsigned> components;
104-
unsigned numComponents = CG.computeConnectedComponents(typeVars, components);
99+
auto components = CG.computeConnectedComponents(CS.TypeVariables);
100+
unsigned numComponents =
101+
components.size() + CG.getOrphanedConstraints().size();
105102
if (numComponents < 2) {
106103
componentSteps.push_back(llvm::make_unique<ComponentStep>(
107-
CS, 0, /*single=*/true, &CS.InactiveConstraints, Solutions));
104+
CS, 0, &CS.InactiveConstraints, Solutions));
108105
return;
109106
}
110107

111108
Components.resize(numComponents);
112109
PartialSolutions = std::unique_ptr<SmallVector<Solution, 4>[]>(
113110
new SmallVector<Solution, 4>[numComponents]);
114111

115-
for (unsigned i = 0, n = numComponents; i != n; ++i) {
112+
// Add components.
113+
for (unsigned i : indices(components)) {
116114
componentSteps.push_back(llvm::make_unique<ComponentStep>(
117-
CS, i, /*single=*/false, &Components[i], PartialSolutions[i]));
115+
CS, i, &Components[i], std::move(components[i]), PartialSolutions[i]));
116+
}
117+
118+
// Add components for the orphaned constraints.
119+
OrphanedConstraints = CG.takeOrphanedConstraints();
120+
for (unsigned i : range(components.size(), numComponents)) {
121+
auto orphaned = OrphanedConstraints[i - components.size()];
122+
componentSteps.push_back(llvm::make_unique<ComponentStep>(
123+
CS, i, &Components[i], orphaned, PartialSolutions[i]));
118124
}
119125

120126
if (isDebugMode()) {
@@ -129,57 +135,6 @@ void SplitterStep::computeFollowupSteps(
129135
CG.printConnectedComponents(CS.TypeVariables, log);
130136
}
131137

132-
// Map type variables and constraints into appropriate steps.
133-
llvm::DenseMap<TypeVariableType *, unsigned> typeVarComponent;
134-
llvm::DenseMap<Constraint *, unsigned> constraintComponent;
135-
for (unsigned i = 0, n = typeVars.size(); i != n; ++i) {
136-
auto *typeVar = typeVars[i];
137-
// Record the component of this type variable.
138-
typeVarComponent[typeVar] = components[i];
139-
140-
for (auto *constraint : CG[typeVar].getConstraints())
141-
constraintComponent[constraint] = components[i];
142-
}
143-
144-
// Add the orphaned components to the mapping from constraints to components.
145-
unsigned firstOrphanedComponent =
146-
numComponents - CG.getOrphanedConstraints().size();
147-
{
148-
unsigned component = firstOrphanedComponent;
149-
for (auto *constraint : CG.getOrphanedConstraints()) {
150-
// Register this orphan constraint both as associated with
151-
// a given component as a regular constrant, as well as an
152-
// "orphan" constraint, so it can be proccessed correctly.
153-
constraintComponent[constraint] = component;
154-
componentSteps[component]->recordOrphan(constraint);
155-
++component;
156-
}
157-
}
158-
159-
for (auto *typeVar : CS.TypeVariables) {
160-
auto known = typeVarComponent.find(typeVar);
161-
// If current type variable is associated with
162-
// a certain component step, record it as being so.
163-
if (known != typeVarComponent.end()) {
164-
componentSteps[known->second]->record(typeVar);
165-
continue;
166-
}
167-
}
168-
169-
// Transfer all of the constraints from the work list to
170-
// the appropriate component.
171-
auto &workList = CS.InactiveConstraints;
172-
while (!workList.empty()) {
173-
auto *constraint = &workList.front();
174-
workList.pop_front();
175-
assert(constraintComponent.count(constraint) > 0 && "Missed a constraint");
176-
componentSteps[constraintComponent[constraint]]->record(constraint);
177-
}
178-
179-
// Remove all of the orphaned constraints; they'll be re-introduced
180-
// by each component independently.
181-
OrphanedConstraints = CG.takeOrphanedConstraints();
182-
183138
// Create component ordering based on the information associated
184139
// with constraints in each step - e.g. number of disjunctions,
185140
// since components are going to be executed in LIFO order, we'd

lib/Sema/CSStep.h

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#define SWIFT_SEMA_CSSTEP_H
2020

2121
#include "Constraint.h"
22+
#include "ConstraintGraph.h"
2223
#include "ConstraintSystem.h"
2324
#include "swift/AST/Types.h"
2425
#include "llvm/ADT/ArrayRef.h"
@@ -336,7 +337,7 @@ class ComponentStep final : public SolverStep {
336337
std::unique_ptr<Scope> ComponentScope = nullptr;
337338

338339
/// Type variables and constraints "in scope" of this step.
339-
std::vector<TypeVariableType *> TypeVars;
340+
TinyPtrVector<TypeVariableType *> TypeVars;
340341
/// Constraints "in scope" of this step.
341342
ConstraintList *Constraints;
342343

@@ -349,29 +350,51 @@ class ComponentStep final : public SolverStep {
349350
Constraint *OrphanedConstraint = nullptr;
350351

351352
public:
352-
ComponentStep(ConstraintSystem &cs, unsigned index, bool single,
353+
/// Create a single component step.
354+
ComponentStep(ConstraintSystem &cs, unsigned index,
353355
ConstraintList *constraints,
354356
SmallVectorImpl<Solution> &solutions)
355-
: SolverStep(cs, solutions), Index(index), IsSingle(single),
357+
: SolverStep(cs, solutions), Index(index), IsSingle(true),
356358
OriginalScore(getCurrentScore()), OriginalBestScore(getBestScore()),
357359
Constraints(constraints) {}
358360

359-
/// Record a type variable as associated with this step.
360-
void record(TypeVariableType *typeVar) { TypeVars.push_back(typeVar); }
361+
/// Create a component step from a constraint graph component.
362+
ComponentStep(ConstraintSystem &cs, unsigned index,
363+
ConstraintList *constraints,
364+
ConstraintGraph::Component &&component,
365+
SmallVectorImpl<Solution> &solutions)
366+
: SolverStep(cs, solutions), Index(index), IsSingle(false),
367+
OriginalScore(getCurrentScore()), OriginalBestScore(getBestScore()),
368+
Constraints(constraints) {
369+
TypeVars = std::move(component.typeVars);
370+
371+
for (auto constraint : component.constraints) {
372+
constraints->erase(constraint);
373+
record(constraint);
374+
}
375+
}
376+
377+
/// Create a component step for an orphaned constraint.
378+
ComponentStep(ConstraintSystem &cs, unsigned index,
379+
ConstraintList *constraints,
380+
Constraint *orphaned,
381+
SmallVectorImpl<Solution> &solutions)
382+
: SolverStep(cs, solutions), Index(index), IsSingle(false),
383+
OriginalScore(getCurrentScore()), OriginalBestScore(getBestScore()),
384+
Constraints(constraints), OrphanedConstraint(orphaned) {
385+
constraints->erase(orphaned);
386+
record(orphaned);
387+
}
361388

389+
private:
362390
/// Record a constraint as associated with this step.
363391
void record(Constraint *constraint) {
364392
Constraints->push_back(constraint);
365393
if (constraint->getKind() == ConstraintKind::Disjunction)
366394
++NumDisjunctions;
367395
}
368396

369-
/// Record a constraint as associated with this step but which doesn't
370-
/// have any free type variables associated with it.
371-
void recordOrphan(Constraint *constraint) {
372-
assert(!OrphanedConstraint);
373-
OrphanedConstraint = constraint;
374-
}
397+
public:
375398

376399
StepResult take(bool prevFailed) override;
377400
StepResult resume(bool prevFailed) override;

0 commit comments

Comments
 (0)