Skip to content

Commit 1a2d7f5

Browse files
committed
[ConstraintSystem] Reinstate favoring more specialized of two generic overloads.
This was originally commited in 3d32e89, and then backed out in c40fd39 due to concern over behavioral changes. This version avoids the optimization when there are any optional types involved in the signatures of the functions. For these cases, compareDeclarations can return the wrong order at the moment. I have another PR in the works that attempts to begin unraveling some of the issues around fixing the overload comparisons.
1 parent 7321b10 commit 1a2d7f5

File tree

3 files changed

+61
-1
lines changed

3 files changed

+61
-1
lines changed

lib/Sema/ConstraintSystem.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1486,6 +1486,64 @@ ConstraintSystem::getTypeOfMemberReference(
14861486
return { openedType, type };
14871487
}
14881488

1489+
// Performance hack: if there are two generic overloads, and one is
1490+
// more specialized than the other, prefer the more-specialized one.
1491+
static void tryOptimizeGenericDisjunction(ConstraintSystem &cs,
1492+
ArrayRef<OverloadChoice> choices,
1493+
OverloadChoice *&favoredChoice) {
1494+
if (favoredChoice || choices.size() != 2)
1495+
return;
1496+
1497+
const auto &choiceA = choices[0];
1498+
const auto &choiceB = choices[1];
1499+
1500+
if (!choiceA.isDecl() || !choiceB.isDecl())
1501+
return;
1502+
1503+
auto isViable = [](ValueDecl *decl) -> bool {
1504+
assert(decl);
1505+
1506+
auto *AFD = dyn_cast<AbstractFunctionDecl>(decl);
1507+
if (!AFD || !AFD->isGeneric())
1508+
return false;
1509+
1510+
auto funcType = AFD->getInterfaceType();
1511+
auto hasAnyOrOptional = funcType.findIf([](Type type) -> bool {
1512+
if (auto objType = type->getOptionalObjectType())
1513+
return true;
1514+
1515+
return type->isAny();
1516+
});
1517+
1518+
// If function declaration references `Any` or `Any?` type
1519+
// let's not attempt it, because it's unclear
1520+
// without solving which overload is going to be better.
1521+
return !hasAnyOrOptional;
1522+
};
1523+
1524+
auto *declA = choiceA.getDecl();
1525+
auto *declB = choiceB.getDecl();
1526+
1527+
if (!isViable(declA) || !isViable(declB))
1528+
return;
1529+
1530+
auto &TC = cs.TC;
1531+
auto *DC = cs.DC;
1532+
1533+
switch (TC.compareDeclarations(DC, declA, declB)) {
1534+
case Comparison::Better:
1535+
favoredChoice = const_cast<OverloadChoice *>(&choiceA);
1536+
break;
1537+
1538+
case Comparison::Worse:
1539+
favoredChoice = const_cast<OverloadChoice *>(&choiceB);
1540+
break;
1541+
1542+
case Comparison::Unordered:
1543+
break;
1544+
}
1545+
}
1546+
14891547
void ConstraintSystem::addOverloadSet(Type boundType,
14901548
ArrayRef<OverloadChoice> choices,
14911549
DeclContext *useDC,
@@ -1500,6 +1558,8 @@ void ConstraintSystem::addOverloadSet(Type boundType,
15001558
return;
15011559
}
15021560

1561+
tryOptimizeGenericDisjunction(*this, choices, favoredChoice);
1562+
15031563
SmallVector<Constraint *, 4> overloads;
15041564

15051565
// As we do for other favored constraints, if a favored overload has been

validation-test/Sema/type_checker_perf/slow/more_specialized_generic_func.swift.gyb renamed to validation-test/Sema/type_checker_perf/fast/more_specialized_generic_func.swift.gyb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %scale-test --invert-result --begin 1 --end 10 --step 1 --select incrementScopeCounter %s --expected-exit-code 0
1+
// RUN: %scale-test --begin 1 --end 10 --step 1 --select incrementScopeCounter %s --expected-exit-code 0
22
// REQUIRES: OS=macosx
33
// REQUIRES: asserts
44

0 commit comments

Comments
 (0)