Skip to content

Commit 1a60685

Browse files
committed
Sema: Address the FIXME in ConstraintGraph::mergeNodes()
1 parent 5690add commit 1a60685

File tree

4 files changed

+60
-49
lines changed

4 files changed

+60
-49
lines changed

include/swift/Sema/ConstraintGraph.h

+8-1
Original file line numberDiff line numberDiff line change
@@ -261,10 +261,17 @@ class ConstraintGraph {
261261
/// Primitive form for SolverTrail::Change::undo().
262262
void removeConstraint(TypeVariableType *typeVar, Constraint *constraint);
263263

264+
/// Prepare to merge the given node into some other node.
265+
///
266+
/// This records graph changes that must be undone after the merge has
267+
/// been undone.
268+
void mergeNodesPre(TypeVariableType *typeVar2);
269+
264270
/// Merge the two nodes for the two given type variables.
265271
///
266272
/// The type variables must actually have been merged already; this
267-
/// operation merges the two nodes.
273+
/// operation merges the two nodes. This also records graph changes
274+
/// that must be undone before the merge can be undone.
268275
void mergeNodes(TypeVariableType *typeVar1, TypeVariableType *typeVar2);
269276

270277
/// Bind the given type variable to the given fixed type.

include/swift/Sema/ConstraintSystem.h

+1-6
Original file line numberDiff line numberDiff line change
@@ -555,12 +555,7 @@ class TypeVariableType::Implementation {
555555
/// \param trail The record of state changes.
556556
void mergeEquivalenceClasses(TypeVariableType *other,
557557
constraints::SolverTrail *trail) {
558-
// Merge the equivalence classes corresponding to these two type
559-
// variables. Always merge 'up' the constraint stack, because it is simpler.
560-
if (getID() > other->getImpl().getID()) {
561-
other->getImpl().mergeEquivalenceClasses(getTypeVariable(), trail);
562-
return;
563-
}
558+
ASSERT(getID() < other->getImpl().getID());
564559

565560
auto otherRep = other->getImpl().getRepresentative(trail);
566561
if (trail)

lib/Sema/ConstraintGraph.cpp

+45-40
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,10 @@ ConstraintGraph::lookupNode(TypeVariableType *typeVar) {
8989
// If this type variable is not the representative of its equivalence class,
9090
// add it to its representative's set of equivalences.
9191
auto typeVarRep = CS.getRepresentative(typeVar);
92-
if (typeVar != typeVarRep)
93-
mergeNodes(typeVar, typeVarRep);
92+
if (typeVar != typeVarRep) {
93+
mergeNodesPre(typeVar);
94+
mergeNodes(typeVarRep, typeVar);
95+
}
9496
else if (auto fixed = CS.getFixedType(typeVarRep)) {
9597
// Bind the type variable.
9698
bindTypeVariable(typeVar, fixed);
@@ -251,32 +253,6 @@ void ConstraintGraphNode::addToEquivalenceClass(
251253
if (EquivalenceClass.empty())
252254
EquivalenceClass.push_back(getTypeVariable());
253255
EquivalenceClass.append(typeVars.begin(), typeVars.end());
254-
255-
{
256-
for (auto *newMember : typeVars) {
257-
auto &node = CG[newMember];
258-
259-
for (auto *constraint : node.getConstraints()) {
260-
introduceToInference(constraint);
261-
262-
if (!isUsefulForReferencedVars(constraint))
263-
continue;
264-
265-
notifyReferencedVars([&](ConstraintGraphNode &referencedVar) {
266-
referencedVar.introduceToInference(constraint);
267-
});
268-
}
269-
270-
// FIXME: Perhaps this also needs to be split up into two stages,
271-
// where the first stage runs before we merge the equivalence
272-
// classes
273-
node.notifyReferencingVars(
274-
[&](ConstraintGraphNode &node, Constraint *constraint) {
275-
node.retractFromInference(constraint);
276-
node.introduceToInference(constraint);
277-
});
278-
}
279-
}
280256
}
281257

282258
void ConstraintGraphNode::truncateEquivalenceClass(unsigned prevSize) {
@@ -525,31 +501,60 @@ void ConstraintGraph::removeConstraint(TypeVariableType *typeVar,
525501
OrphanedConstraints.pop_back();
526502
}
527503

504+
void ConstraintGraph::mergeNodesPre(TypeVariableType *typeVar2) {
505+
// Merge equivalence class from the non-representative type variable.
506+
auto &nonRepNode = (*this)[typeVar2];
507+
508+
for (auto *newMember : nonRepNode.getEquivalenceClassUnsafe()) {
509+
auto &node = (*this)[newMember];
510+
511+
node.notifyReferencingVars(
512+
[&](ConstraintGraphNode &node, Constraint *constraint) {
513+
node.retractFromInference(constraint);
514+
});
515+
}
516+
}
517+
528518
void ConstraintGraph::mergeNodes(TypeVariableType *typeVar1,
529519
TypeVariableType *typeVar2) {
530-
assert(CS.getRepresentative(typeVar1) == CS.getRepresentative(typeVar2) &&
531-
"type representatives don't match");
532-
533520
// Retrieve the node for the representative that we're merging into.
534-
auto typeVarRep = CS.getRepresentative(typeVar1);
535-
auto &repNode = (*this)[typeVarRep];
521+
ASSERT(CS.getRepresentative(typeVar1) == typeVar1);
536522

537-
// Retrieve the node for the non-representative.
538-
assert((typeVar1 == typeVarRep || typeVar2 == typeVarRep) &&
539-
"neither type variable is the new representative?");
540-
auto typeVarNonRep = typeVar1 == typeVarRep? typeVar2 : typeVar1;
523+
auto &repNode = (*this)[typeVar1];
541524

542525
// Record the change, if there are active scopes.
543526
if (CS.isRecordingChanges()) {
544527
CS.recordChange(
545528
SolverTrail::Change::ExtendedEquivalenceClass(
546-
typeVarRep,
529+
typeVar1,
547530
repNode.getEquivalenceClass().size()));
548531
}
549532

550533
// Merge equivalence class from the non-representative type variable.
551-
auto &nonRepNode = (*this)[typeVarNonRep];
552-
repNode.addToEquivalenceClass(nonRepNode.getEquivalenceClassUnsafe());
534+
auto &nonRepNode = (*this)[typeVar2];
535+
536+
auto typeVars = nonRepNode.getEquivalenceClassUnsafe();
537+
repNode.addToEquivalenceClass(typeVars);
538+
539+
for (auto *newMember : typeVars) {
540+
auto &node = (*this)[newMember];
541+
542+
for (auto *constraint : node.getConstraints()) {
543+
repNode.introduceToInference(constraint);
544+
545+
if (!isUsefulForReferencedVars(constraint))
546+
continue;
547+
548+
repNode.notifyReferencedVars([&](ConstraintGraphNode &referencedVar) {
549+
referencedVar.introduceToInference(constraint);
550+
});
551+
}
552+
553+
node.notifyReferencingVars(
554+
[&](ConstraintGraphNode &node, Constraint *constraint) {
555+
node.introduceToInference(constraint);
556+
});
557+
}
553558
}
554559

555560
void ConstraintGraph::bindTypeVariable(TypeVariableType *typeVar, Type fixed) {

lib/Sema/ConstraintSystem.cpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,13 @@ void ConstraintSystem::mergeEquivalenceClasses(TypeVariableType *typeVar1,
173173
assert(typeVar2 == getRepresentative(typeVar2) &&
174174
"typeVar2 is not the representative");
175175
assert(typeVar1 != typeVar2 && "cannot merge type with itself");
176-
typeVar1->getImpl().mergeEquivalenceClasses(typeVar2, getTrail());
177176

178-
// Merge nodes in the constraint graph.
177+
// Always merge 'up' the constraint stack, because it is simpler.
178+
if (typeVar1->getImpl().getID() > typeVar2->getImpl().getID())
179+
std::swap(typeVar1, typeVar2);
180+
181+
CG.mergeNodesPre(typeVar2);
182+
typeVar1->getImpl().mergeEquivalenceClasses(typeVar2, getTrail());
179183
CG.mergeNodes(typeVar1, typeVar2);
180184

181185
if (updateWorkList) {

0 commit comments

Comments
 (0)