Skip to content

Sema: Ignore inactive type variables in addTypeVariableConstraintsToWorkList() #78888

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 10 additions & 17 deletions include/swift/Sema/ConstraintGraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -300,25 +300,18 @@ class ConstraintGraph {
/// to a type variable.
void introduceToInference(TypeVariableType *typeVar, Type fixedType);

/// Describes which constraints \c gatherConstraints should gather.
enum class GatheringKind {
/// Gather constraints associated with all of the variables within the
/// same equivalence class as the given type variable, as well as its
/// immediate fixed bindings.
EquivalenceClass,
/// Gather all constraints that mention this type variable or type variables
/// that it is a fixed binding of. Unlike EquivalenceClass, this looks
/// through transitive fixed bindings. This can be used to find all the
/// constraints that may be affected when binding a type variable.
AllMentions,
};
/// Gather constraints associated with all of the variables within the
/// same equivalence class as the given type variable, as well as its
/// immediate fixed bindings.
llvm::TinyPtrVector<Constraint *>
gatherAllConstraints(TypeVariableType *typeVar);

/// Gather the set of constraints that involve the given type variable,
/// i.e., those constraints that will be affected when the type variable
/// gets merged or bound to a fixed type.
/// Gather all constraints that mention this type variable or type variables
/// that it is a fixed binding of. Unlike EquivalenceClass, this looks
/// through transitive fixed bindings. This can be used to find all the
/// constraints that may be affected when binding a type variable.
llvm::TinyPtrVector<Constraint *>
gatherConstraints(TypeVariableType *typeVar,
GatheringKind kind,
gatherNearbyConstraints(TypeVariableType *typeVar,
llvm::function_ref<bool(Constraint *)> acceptConstraint =
[](Constraint *constraint) { return true; });

Expand Down
8 changes: 4 additions & 4 deletions lib/Sema/CSOptimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@ NullablePtr<Constraint> getApplicableFnConstraint(ConstraintGraph &CG,
if (!boundVar)
return nullptr;

auto constraints = CG.gatherConstraints(
boundVar, ConstraintGraph::GatheringKind::EquivalenceClass,
auto constraints = CG.gatherNearbyConstraints(
boundVar,
[](Constraint *constraint) {
return constraint->getKind() == ConstraintKind::ApplicableFunction;
});
Expand Down Expand Up @@ -1129,8 +1129,8 @@ selectBestBindingDisjunction(ConstraintSystem &cs,
if (!firstBindDisjunction)
firstBindDisjunction = disjunction;

auto constraints = cs.getConstraintGraph().gatherConstraints(
typeVar, ConstraintGraph::GatheringKind::EquivalenceClass,
auto constraints = cs.getConstraintGraph().gatherNearbyConstraints(
typeVar,
[](Constraint *constraint) {
return constraint->getKind() == ConstraintKind::Conversion;
});
Expand Down
4 changes: 2 additions & 2 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15843,8 +15843,8 @@ ConstraintSystem::addKeyPathApplicationRootConstraint(Type root, ConstraintLocat
if (!typeVar)
return;

auto constraints = CG.gatherConstraints(
typeVar, ConstraintGraph::GatheringKind::EquivalenceClass,
auto constraints = CG.gatherNearbyConstraints(
typeVar,
[&keyPathExpr](Constraint *constraint) -> bool {
if (constraint->getKind() != ConstraintKind::KeyPath)
return false;
Expand Down
18 changes: 14 additions & 4 deletions lib/Sema/CSSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1309,8 +1309,8 @@ ConstraintSystem::findConstraintThroughOptionals(
while (visitedVars.insert(rep).second) {
// Look for a disjunction that binds this type variable to an overload set.
TypeVariableType *optionalObjectTypeVar = nullptr;
auto constraints = getConstraintGraph().gatherConstraints(
rep, ConstraintGraph::GatheringKind::EquivalenceClass,
auto constraints = getConstraintGraph().gatherNearbyConstraints(
rep,
[&](Constraint *match) {
// If we have an "optional object of" constraint, we may need to
// look through it to find the constraint we're looking for.
Expand Down Expand Up @@ -1918,9 +1918,8 @@ void DisjunctionChoice::propagateConversionInfo(ConstraintSystem &cs) const {
}
}

auto constraints = cs.CG.gatherConstraints(
auto constraints = cs.CG.gatherNearbyConstraints(
typeVar,
ConstraintGraph::GatheringKind::EquivalenceClass,
[](Constraint *constraint) -> bool {
switch (constraint->getKind()) {
case ConstraintKind::Conversion:
Expand All @@ -1946,6 +1945,17 @@ bool ConjunctionElement::attempt(ConstraintSystem &cs) const {
llvm::SmallPtrSet<TypeVariableType *, 4> referencedVars;
findReferencedVariables(cs, referencedVars);

if (cs.isDebugMode()) {
auto indent = cs.solverState->getCurrentIndent();
auto &log = llvm::errs().indent(indent);
log << "(Element type variables in scope: ";
interleave(
referencedVars,
[&](TypeVariableType *typeVar) { log << "$T" << typeVar->getID(); },
[&] { log << ", "; });
log << ")\n";
}

for (auto *typeVar : referencedVars)
cs.addTypeVariable(typeVar);
}
Expand Down
51 changes: 20 additions & 31 deletions lib/Sema/ConstraintGraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -552,31 +552,26 @@ void ConstraintGraph::retractBindings(TypeVariableType *typeVar,

#pragma mark Algorithms

/// Perform a depth-first search.
///
/// \param cg The constraint graph.
/// \param typeVar The type variable we're searching from.
/// \param visitConstraint Called before considering a constraint.
/// \param visitedConstraints Set of already-visited constraints, used
/// internally to avoid duplicated work.
static void depthFirstSearch(
ConstraintGraph &cg,
TypeVariableType *typeVar,
llvm::function_ref<void(Constraint *)> visitConstraint,
llvm::SmallPtrSet<TypeVariableType *, 4> &typeVars,
llvm::TinyPtrVector<Constraint *> &constraints,
llvm::SmallPtrSet<Constraint *, 8> &visitedConstraints) {
// If we're not looking at this type variable right now because we're
// solving a conjunction element, don't consider its adjacencies.
if (!cg.getConstraintSystem().isActiveTypeVariable(typeVar))
return;

// Visit this node. If we've already seen it, bail out.
if (!typeVars.insert(typeVar).second)
return;

// Local function to visit adjacent type variables.
auto visitAdjacencies = [&](ArrayRef<TypeVariableType *> adjTypeVars) {
for (auto adj : adjTypeVars) {
if (adj == typeVar)
continue;

// Recurse into this node.
depthFirstSearch(cg, adj, visitConstraint, typeVars, visitedConstraints);
if (adj != typeVar)
depthFirstSearch(cg, adj, typeVars, constraints, visitedConstraints);
}
};

Expand All @@ -587,7 +582,7 @@ static void depthFirstSearch(
if (!visitedConstraints.insert(constraint).second)
continue;

visitConstraint(constraint);
constraints.push_back(constraint);
}

// Visit all of the other nodes in the equivalence class.
Expand All @@ -606,28 +601,22 @@ static void depthFirstSearch(
visitAdjacencies(node.getReferencedVars());
}

llvm::TinyPtrVector<Constraint *> ConstraintGraph::gatherConstraints(
TypeVariableType *typeVar, GatheringKind kind,
llvm::function_ref<bool(Constraint *)> acceptConstraintFn) {
llvm::TinyPtrVector<Constraint *> ConstraintGraph::gatherAllConstraints(
TypeVariableType *typeVar) {
llvm::TinyPtrVector<Constraint *> constraints;
llvm::SmallPtrSet<TypeVariableType *, 4> typeVars;
llvm::SmallPtrSet<Constraint *, 8> visitedConstraints;

if (kind == GatheringKind::AllMentions) {
// If we've been asked for "all mentions" of a type variable, search for
// constraints involving both it and its fixed bindings.
depthFirstSearch(
*this, typeVar,
[&](Constraint *constraint) {
if (acceptConstraintFn(constraint))
constraints.push_back(constraint);
},
typeVars, visitedConstraints);
return constraints;
}
depthFirstSearch(*this, typeVar, typeVars, constraints, visitedConstraints);
return constraints;
}

// Otherwise only search in the type var's equivalence class and immediate
// fixed bindings.
llvm::TinyPtrVector<Constraint *> ConstraintGraph::gatherNearbyConstraints(
TypeVariableType *typeVar,
llvm::function_ref<bool(Constraint *)> acceptConstraintFn) {
llvm::TinyPtrVector<Constraint *> constraints;
llvm::SmallPtrSet<TypeVariableType *, 4> typeVars;
llvm::SmallPtrSet<Constraint *, 8> visitedConstraints;

// Local function to add constraints.
auto addTypeVarConstraints = [&](TypeVariableType *adjTypeVar) {
Expand Down
3 changes: 1 addition & 2 deletions lib/Sema/ConstraintSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,7 @@ void ConstraintSystem::assignFixedType(TypeVariableType *typeVar, Type type,
void ConstraintSystem::addTypeVariableConstraintsToWorkList(
TypeVariableType *typeVar) {
// Activate the constraints affected by a change to this type variable.
auto gatheringKind = ConstraintGraph::GatheringKind::AllMentions;
for (auto *constraint : CG.gatherConstraints(typeVar, gatheringKind))
for (auto *constraint : CG.gatherAllConstraints(typeVar))
if (!constraint->isActive())
activateConstraint(constraint);
}
Expand Down
4 changes: 2 additions & 2 deletions lib/Sema/TypeOfReference.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2044,8 +2044,8 @@ void ConstraintSystem::bindOverloadType(
increaseScore(SK_KeyPathSubscript, locator);

auto boundTypeVar = boundType->castTo<TypeVariableType>();
auto constraints = getConstraintGraph().gatherConstraints(
boundTypeVar, ConstraintGraph::GatheringKind::EquivalenceClass,
auto constraints = getConstraintGraph().gatherNearbyConstraints(
boundTypeVar,
[](Constraint *constraint) {
return constraint->getKind() == ConstraintKind::ApplicableFunction;
});
Expand Down
13 changes: 13 additions & 0 deletions test/Constraints/rdar143340082.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// RUN: %target-typecheck-verify-swift

struct Test {
var v: String
var i: Int
}

do {
let _ = Array(1 ... 20).map { i in
_ = 0
return Test(v: "\(i * 1000)", i: 1)
}
}