Skip to content

Commit 8d03c68

Browse files
authored
Merge pull request #59971 from amritpan/improve-connected-components-printing
[ConstraintSystem] Improve connected components printing in the type inference algorithm debug output
2 parents 6471cd2 + 6d55c52 commit 8d03c68

File tree

9 files changed

+207
-44
lines changed

9 files changed

+207
-44
lines changed

include/swift/Sema/CSBindings.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -546,8 +546,6 @@ class BindingSet {
546546
}
547547

548548
void dump(llvm::raw_ostream &out, unsigned indent) const;
549-
void dump(TypeVariableType *typeVar, llvm::raw_ostream &out,
550-
unsigned indent = 0) const LLVM_ATTRIBUTE_USED;
551549

552550
private:
553551
void addBinding(PotentialBinding binding);

include/swift/Sema/ConstraintGraph.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,7 @@ class ConstraintGraph {
387387
/// Print the graph.
388388
void print(ArrayRef<TypeVariableType *> typeVars, llvm::raw_ostream &out);
389389
void dump(llvm::raw_ostream &out);
390+
void dumpActiveScopeChanges(llvm::raw_ostream &out, unsigned indent = 0);
390391

391392
// FIXME: Potentially side-effectful.
392393
SWIFT_DEBUG_HELPER(void dump());
@@ -458,6 +459,7 @@ class ConstraintGraph {
458459
/// Each change can be undone (once, and in reverse order) by calling the
459460
/// undo() method.
460461
class Change {
462+
public:
461463
/// The kind of change.
462464
ChangeKind Kind;
463465

@@ -482,7 +484,6 @@ class ConstraintGraph {
482484
} Binding;
483485
};
484486

485-
public:
486487
Change() : Kind(ChangeKind::AddedTypeVariable), TypeVar(nullptr) { }
487488

488489
/// Create a change that added a type variable.

include/swift/Sema/ConstraintGraphScope.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ class ConstraintGraphScope {
5050
public:
5151
explicit ConstraintGraphScope(ConstraintGraph &CG);
5252
~ConstraintGraphScope();
53+
54+
/// Get number of changes recorded at the start of the current active scope.
55+
unsigned getStartIdx() {
56+
return NumChanges;
57+
}
5358
};
5459

5560
} // end namespace constraints

include/swift/Sema/ConstraintSystem.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5557,7 +5557,10 @@ class ConstraintSystem {
55575557
Type wrapperType, Type paramType, ParamDecl *param, Identifier argLabel,
55585558
ConstraintKind matchKind, ConstraintLocatorBuilder locator);
55595559

5560-
Optional<BindingSet> determineBestBindings();
5560+
/// Determine whether given type variable with its set of bindings is viable
5561+
/// to be attempted on the next step of the solver.
5562+
Optional<BindingSet> determineBestBindings(
5563+
llvm::function_ref<void(const BindingSet &)> onCandidate);
55615564

55625565
/// Get bindings for the given type variable based on current
55635566
/// state of the constraint system.

lib/Sema/CSBindings.cpp

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,8 @@ BindingSet::BindingScore BindingSet::formBindingScore(const BindingSet &b) {
742742
-numNonDefaultableBindings);
743743
}
744744

745-
Optional<BindingSet> ConstraintSystem::determineBestBindings() {
745+
Optional<BindingSet> ConstraintSystem::determineBestBindings(
746+
llvm::function_ref<void(const BindingSet &)> onCandidate) {
746747
// Look for potential type variable bindings.
747748
Optional<BindingSet> bestBindings;
748749
llvm::SmallDenseMap<TypeVariableType *, BindingSet> cache;
@@ -804,9 +805,7 @@ Optional<BindingSet> ConstraintSystem::determineBestBindings() {
804805
if (!bindings || !isViable)
805806
continue;
806807

807-
if (isDebugMode()) {
808-
bindings.dump(typeVar, llvm::errs(), solverState->getCurrentIndent());
809-
}
808+
onCandidate(bindings);
810809

811810
// If these are the first bindings, or they are better than what
812811
// we saw before, use them instead.
@@ -1652,21 +1651,15 @@ static std::string getCollectionLiteralAsString(KnownProtocolKind KPK) {
16521651
#undef ENTRY
16531652
}
16541653

1655-
void BindingSet::dump(TypeVariableType *typeVar, llvm::raw_ostream &out,
1656-
unsigned indent) const {
1657-
out.indent(indent);
1658-
out << "(";
1659-
if (typeVar)
1660-
out << "$T" << typeVar->getImpl().getID();
1661-
dump(out, 1);
1662-
out << ")\n";
1663-
}
1664-
16651654
void BindingSet::dump(llvm::raw_ostream &out, unsigned indent) const {
16661655
PrintOptions PO;
16671656
PO.PrintTypesForDebugging = true;
16681657

16691658
out.indent(indent);
1659+
out << "(";
1660+
if (auto typeVar = getTypeVariable())
1661+
out << "$T" << typeVar->getImpl().getID() << " ";
1662+
16701663
std::vector<std::string> attributes;
16711664
if (isDirectHole())
16721665
attributes.push_back("hole");
@@ -1778,6 +1771,7 @@ void BindingSet::dump(llvm::raw_ostream &out, unsigned indent) const {
17781771
}
17791772
out << "] ";
17801773
}
1774+
out << ")\n";
17811775
}
17821776

17831777
// Given a possibly-Optional type, return the direct superclass of the

lib/Sema/CSStep.cpp

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -346,8 +346,45 @@ StepResult ComponentStep::take(bool prevFailed) {
346346

347347
/// Try to figure out what this step is going to be,
348348
/// after the scope has been established.
349+
SmallString<64> potentialBindings;
350+
llvm::raw_svector_ostream bos(potentialBindings);
351+
352+
auto bestBindings = CS.determineBestBindings([&](const BindingSet &bindings) {
353+
if (CS.isDebugMode() && bindings.hasViableBindings()) {
354+
bindings.dump(bos, CS.solverState->getCurrentIndent() + 2);
355+
}
356+
});
357+
349358
auto *disjunction = CS.selectDisjunction();
350-
auto bestBindings = CS.determineBestBindings();
359+
auto *conjunction = CS.selectConjunction();
360+
361+
if (CS.isDebugMode()) {
362+
PrintOptions PO;
363+
PO.PrintTypesForDebugging = true;
364+
365+
auto &log = getDebugLogger();
366+
if (!potentialBindings.empty()) {
367+
log << "(Potential Binding(s): " << '\n';
368+
log << potentialBindings;
369+
}
370+
log.indent(CS.solverState->getCurrentIndent());
371+
372+
if (disjunction) {
373+
log.indent(2);
374+
log << "Disjunction(s) = [";
375+
auto constraints = disjunction->getNestedConstraints();
376+
log << constraints[0]->getFirstType()->getString(PO);
377+
log << "]";
378+
}
379+
if (conjunction) {
380+
log.indent(2);
381+
log << "Conjunction(s) = [";
382+
auto constraints = conjunction->getNestedConstraints();
383+
log << constraints[0]->getFirstType()->getString(PO);
384+
log << "]";
385+
}
386+
log << ")\n";
387+
}
351388

352389
if (CS.shouldAttemptFixes()) {
353390
if ((bestBindings &&
@@ -486,23 +523,6 @@ StepResult ComponentStep::finalize(bool isSuccess) {
486523

487524
void TypeVariableStep::setup() {
488525
++CS.solverState->NumTypeVariablesBound;
489-
if (CS.isDebugMode()) {
490-
PrintOptions PO;
491-
PO.PrintTypesForDebugging = true;
492-
auto &log = getDebugLogger();
493-
494-
auto initialBindings = Producer.getCurrentBindings();
495-
log << "Initial bindings: ";
496-
interleave(
497-
initialBindings.begin(), initialBindings.end(),
498-
[&](const Binding &binding) {
499-
log << TypeVar->getString(PO)
500-
<< " := " << binding.BindingType->getString(PO);
501-
},
502-
[&log] { log << ", "; });
503-
504-
log << '\n';
505-
}
506526
}
507527

508528
bool TypeVariableStep::attempt(const TypeVariableBinding &choice) {

lib/Sema/CSStep.h

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -466,11 +466,29 @@ class ComponentStep final : public SolverStep {
466466
// to preliminary modify constraint system or log anything.
467467
if (IsSingle)
468468
return;
469-
470-
if (CS.isDebugMode())
471-
getDebugLogger() << "(solving component #" << Index << '\n';
472-
469+
470+
if (CS.isDebugMode()) {
471+
auto &log = getDebugLogger();
472+
log << "(solving component #" << Index << '\n';
473+
}
474+
473475
ComponentScope = std::make_unique<Scope>(*this);
476+
477+
if (CS.isDebugMode()) {
478+
auto &log = getDebugLogger();
479+
log << "Type variables in scope = "
480+
<< "[";
481+
auto typeVars = CS.getTypeVariables();
482+
PrintOptions PO;
483+
PO.PrintTypesForDebugging = true;
484+
interleave(typeVars, [&](TypeVariableType *typeVar) {
485+
Type(typeVar).print(log, PO);
486+
},
487+
[&] {
488+
log << ", ";
489+
});
490+
log << "]" << '\n';
491+
}
474492

475493
// If this component has orphaned constraint attached,
476494
// let's return it to the graph.
@@ -527,6 +545,13 @@ template <typename P> class BindingStep : public SolverStep {
527545
auto scope = std::make_unique<Scope>(CS);
528546
if (attempt(*choice)) {
529547
ActiveChoice.emplace(std::move(scope), *choice);
548+
549+
if (CS.isDebugMode()) {
550+
auto &log = llvm::errs();
551+
auto &CG = CS.getConstraintGraph();
552+
CG.dumpActiveScopeChanges(log, CS.solverState->getCurrentIndent());
553+
}
554+
530555
return suspend(std::make_unique<SplitterStep>(CS, Solutions));
531556
}
532557
}

lib/Sema/ConstraintGraph.cpp

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1558,6 +1558,123 @@ void ConstraintGraph::dump(llvm::raw_ostream &out) {
15581558
print(CS.getTypeVariables(), out);
15591559
}
15601560

1561+
void ConstraintGraph::dumpActiveScopeChanges(llvm::raw_ostream &out,
1562+
unsigned indent) {
1563+
if (Changes.empty())
1564+
return;
1565+
1566+
// Collect Changes for printing.
1567+
std::map<TypeVariableType *, TypeBase *> tvWithboundTypes;
1568+
std::vector<TypeVariableType *> addedTypeVars;
1569+
std::vector<TypeVariableType *> equivTypeVars;
1570+
std::set<Constraint *> addedConstraints;
1571+
std::set<Constraint *> removedConstraints;
1572+
for (unsigned int i = ActiveScope->getStartIdx(); i < Changes.size(); i++) {
1573+
auto change = Changes[i];
1574+
switch (change.Kind) {
1575+
case ChangeKind::BoundTypeVariable:
1576+
tvWithboundTypes.insert(std::pair<TypeVariableType *, TypeBase *>(
1577+
change.Binding.TypeVar, change.Binding.FixedType));
1578+
break;
1579+
case ChangeKind::AddedTypeVariable:
1580+
addedTypeVars.push_back(change.TypeVar);
1581+
break;
1582+
case ChangeKind::ExtendedEquivalenceClass:
1583+
equivTypeVars.push_back(change.EquivClass.TypeVar);
1584+
break;
1585+
case ChangeKind::AddedConstraint:
1586+
addedConstraints.insert(change.TheConstraint);
1587+
break;
1588+
case ChangeKind::RemovedConstraint:
1589+
removedConstraints.insert(change.TheConstraint);
1590+
break;
1591+
}
1592+
}
1593+
1594+
// If there are any constraints that were both added and removed in this set
1595+
// of Changes, remove them from both.
1596+
std::set<Constraint *> intersects;
1597+
set_intersection(addedConstraints.begin(), addedConstraints.end(),
1598+
removedConstraints.begin(), removedConstraints.end(),
1599+
std::inserter(intersects, intersects.begin()));
1600+
llvm::set_subtract(addedConstraints, intersects);
1601+
llvm::set_subtract(removedConstraints, intersects);
1602+
1603+
// Print out Changes.
1604+
PrintOptions PO;
1605+
PO.PrintTypesForDebugging = true;
1606+
out.indent(indent);
1607+
out << "(Changes:\n";
1608+
if (!tvWithboundTypes.empty()) {
1609+
out.indent(indent + 2);
1610+
out << "(Newly Bound: \n";
1611+
for (const auto &tvWithType : tvWithboundTypes) {
1612+
out.indent(indent + 4);
1613+
out << "> $T" << tvWithType.first->getImpl().getID() << " := ";
1614+
tvWithType.second->print(out, PO);
1615+
out << '\n';
1616+
}
1617+
out.indent(indent + 2);
1618+
out << ")\n";
1619+
}
1620+
if (!addedTypeVars.empty()) {
1621+
out.indent(indent + 2);
1622+
auto heading = (addedTypeVars.size() > 1) ? "(New Type Variables: \n"
1623+
: "(New Type Variable: \n";
1624+
out << heading;
1625+
for (const auto &typeVar : addedTypeVars) {
1626+
out.indent(indent + 4);
1627+
out << "> $T" << typeVar->getImpl().getID();
1628+
out << '\n';
1629+
}
1630+
out.indent(indent + 2);
1631+
out << ")\n";
1632+
}
1633+
if (!equivTypeVars.empty()) {
1634+
out.indent(indent + 2);
1635+
auto heading = (equivTypeVars.size() > 1) ? "(New Equivalences: \n"
1636+
: "(New Equivalence: \n";
1637+
out << heading;
1638+
for (const auto &typeVar : equivTypeVars) {
1639+
out.indent(indent + 4);
1640+
out << "> $T" << typeVar->getImpl().getID();
1641+
out << '\n';
1642+
}
1643+
out.indent(indent + 2);
1644+
out << ")\n";
1645+
}
1646+
if (!addedConstraints.empty()) {
1647+
out.indent(indent + 2);
1648+
auto heading = (addedConstraints.size() > 1) ? "(Added Constraints: \n"
1649+
: "(Added Constraint: \n";
1650+
out << heading;
1651+
for (const auto &constraint : addedConstraints) {
1652+
out.indent(indent + 4);
1653+
out << "> ";
1654+
constraint->print(out, &CS.getASTContext().SourceMgr);
1655+
out << '\n';
1656+
}
1657+
out.indent(indent + 2);
1658+
out << ")\n";
1659+
}
1660+
if (!removedConstraints.empty()) {
1661+
out.indent(indent + 2);
1662+
auto heading = (removedConstraints.size() > 1) ? "(Removed Constraints: \n"
1663+
: "(Removed Constraint: \n";
1664+
out << heading;
1665+
for (const auto &constraint : removedConstraints) {
1666+
out.indent(indent + 4);
1667+
out << "> ";
1668+
constraint->print(out, &CS.getASTContext().SourceMgr);
1669+
out << '\n';
1670+
}
1671+
out.indent(indent + 2);
1672+
out << ")\n";
1673+
}
1674+
out.indent(indent);
1675+
out << ")\n";
1676+
}
1677+
15611678
void ConstraintGraph::printConnectedComponents(
15621679
ArrayRef<TypeVariableType *> typeVars,
15631680
llvm::raw_ostream &out) {

test/Constraints/one_way_solve.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,16 @@ func testTernaryOneWayOverload(b: Bool) {
2828
// CHECK: 0: $T2 $T3 $T4
2929

3030
// CHECK: solving component #1
31-
// CHECK: Initial bindings: $T11 := Int8, $T11 := Int16
31+
// CHECK: (attempting type variable $T11 := Int8
3232

3333
// CHECK: solving component #1
34-
// CHECK: Initial bindings: $T11 := Int8, $T11 := Int16
34+
// CHECK: (attempting type variable $T11 := Int8
3535

3636
// CHECK: solving component #1
37-
// CHECK: Initial bindings: $T11 := Int8, $T11 := Int16
37+
// CHECK: (attempting type variable $T11 := Int8
3838

3939
// CHECK: solving component #1
40-
// CHECK: Initial bindings: $T11 := Int8
40+
// CHECK: (attempting type variable $T11 := Int8
4141
// CHECK: (found solution: [non-default literal(s) = 2] [use of overloaded unapplied function(s) = 2])
4242

4343
// CHECK: (composed solution: [non-default literal(s) = 2] [use of overloaded unapplied function(s) = 2])

0 commit comments

Comments
 (0)