Skip to content

Commit ab6d92b

Browse files
gregomnihborla
authored andcommitted
Favor operators based on existing binds via both basename and type
1 parent b06f749 commit ab6d92b

File tree

3 files changed

+47
-8
lines changed

3 files changed

+47
-8
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2467,6 +2467,16 @@ class ConstraintSystem {
24672467
favoredConstraints.push_back(constraint);
24682468
}
24692469

2470+
/// Whether or not the given constraint is only favored during this scope.
2471+
bool isTemporarilyFavored(Constraint *constraint) {
2472+
assert(constraint->isFavored());
2473+
2474+
for (auto test : favoredConstraints)
2475+
if (test == constraint)
2476+
return true;
2477+
return false;
2478+
}
2479+
24702480
private:
24712481
/// The list of constraints that have been retired along the
24722482
/// current path, this list is used in LIFO fashion when constraints

lib/Sema/CSSolver.cpp

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2013,7 +2013,8 @@ static Constraint *tryOptimizeGenericDisjunction(
20132013
llvm_unreachable("covered switch");
20142014
}
20152015

2016-
// Performance hack: favor operator overloads with types we're already binding elsewhere in this expression.
2016+
// Performance hack: favor operator overloads with decl or type we're already
2017+
// binding elsewhere in this expression.
20172018
static void existingOperatorBindingsForDisjunction(ConstraintSystem &CS, ArrayRef<Constraint *> constraints, SmallVectorImpl<Constraint *> &found) {
20182019
auto *choice = constraints.front();
20192020
if (choice->getKind() != ConstraintKind::BindOverload)
@@ -2025,6 +2026,9 @@ static void existingOperatorBindingsForDisjunction(ConstraintSystem &CS, ArrayRe
20252026
auto decl = overload.getDecl();
20262027
if (!decl->isOperator())
20272028
return;
2029+
auto baseName = decl->getBaseName();
2030+
2031+
SmallSet<TypeBase *, 8> typesFound;
20282032

20292033
for (auto overload : CS.getResolvedOverloads()) {
20302034
auto resolved = overload.second;
@@ -2035,12 +2039,33 @@ static void existingOperatorBindingsForDisjunction(ConstraintSystem &CS, ArrayRe
20352039
if (!representativeDecl->isOperator())
20362040
continue;
20372041

2038-
for (auto *constraint : constraints) {
2039-
if (constraint->isFavored())
2042+
if (representativeDecl->getBaseName() == baseName) {
2043+
// Favor exactly the same decl, if we have a binding to the same name.
2044+
for (auto *constraint : constraints) {
2045+
if (constraint->isFavored())
2046+
continue;
2047+
auto choice = constraint->getOverloadChoice();
2048+
if (choice.getDecl() == representativeDecl) {
2049+
found.push_back(constraint);
2050+
break;
2051+
}
2052+
}
2053+
} else {
2054+
// Favor the same type, if we have a binding to an operator of that type.
2055+
auto representativeType = representativeDecl->getInterfaceType();
2056+
if (typesFound.count(representativeType.getPointer()))
20402057
continue;
2041-
auto choice = constraint->getOverloadChoice();
2042-
if (choice.getDecl()->getInterfaceType()->isEqual(representativeDecl->getInterfaceType()))
2043-
found.push_back(constraint);
2058+
typesFound.insert(representativeType.getPointer());
2059+
2060+
for (auto *constraint : constraints) {
2061+
if (constraint->isFavored())
2062+
continue;
2063+
auto choice = constraint->getOverloadChoice();
2064+
if (choice.getDecl()->getInterfaceType()->isEqual(representativeType)) {
2065+
found.push_back(constraint);
2066+
break;
2067+
}
2068+
}
20442069
}
20452070
}
20462071
}

lib/Sema/CSStep.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -615,8 +615,12 @@ bool DisjunctionStep::shortCircuitDisjunctionAt(
615615
auto &ctx = CS.getASTContext();
616616

617617
// If the successfully applied constraint is favored, we'll consider that to
618-
// be the "best".
619-
if (lastSuccessfulChoice->isFavored() && !currentChoice->isFavored()) {
618+
// be the "best". If it was only temporarily favored because it matched other
619+
// operator bindings, we can even short-circuit other favored constraints.
620+
if (lastSuccessfulChoice->isFavored() &&
621+
(!currentChoice->isFavored() ||
622+
(CS.solverState->isTemporarilyFavored(lastSuccessfulChoice) &&
623+
!CS.solverState->isTemporarilyFavored(currentChoice)))) {
620624
#if !defined(NDEBUG)
621625
if (lastSuccessfulChoice->getKind() == ConstraintKind::BindOverload) {
622626
auto overloadChoice = lastSuccessfulChoice->getOverloadChoice();

0 commit comments

Comments
 (0)