Skip to content

Commit 5b4a332

Browse files
committed
[ConstraintSystem] Sort the designated types based on actual argument types.
In cases where we have multiple designated types, sort the types that were designated for this operator based on any information we can gather about actual argument types at usage sites. We can consider extending this further in a future commit to ignore designated types when we have concrete type information that we are confident of.
1 parent 23476e5 commit 5b4a332

File tree

3 files changed

+86
-3
lines changed

3 files changed

+86
-3
lines changed

lib/Sema/CSSolver.cpp

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1683,14 +1683,91 @@ getOperatorDesignatedNominalTypes(Constraint *bindOverload) {
16831683
return operatorDecl->getDesignatedNominalTypes();
16841684
}
16851685

1686+
void ConstraintSystem::sortDesignatedTypes(
1687+
SmallVectorImpl<NominalTypeDecl *> &nominalTypes,
1688+
Constraint *bindOverload) {
1689+
auto *tyvar = bindOverload->getFirstType()->castTo<TypeVariableType>();
1690+
llvm::SetVector<Constraint *> applicableFns;
1691+
getConstraintGraph().gatherConstraints(
1692+
tyvar, applicableFns, ConstraintGraph::GatheringKind::EquivalenceClass,
1693+
[](Constraint *match) {
1694+
return match->getKind() == ConstraintKind::ApplicableFunction;
1695+
});
1696+
1697+
// FIXME: This is not true when we run the constraint optimizer.
1698+
// assert(applicableFns.size() <= 1);
1699+
1700+
// We have a disjunction for an operator but no application of it,
1701+
// so it's being passed as an argument.
1702+
if (applicableFns.size() == 0)
1703+
return;
1704+
1705+
// FIXME: We have more than one applicable per disjunction as a
1706+
// result of merging disjunction type variables. We may want
1707+
// to rip that out at some point.
1708+
Constraint *foundApplicable = nullptr;
1709+
SmallVector<Optional<Type>, 2> argumentTypes;
1710+
for (auto *applicableFn : applicableFns) {
1711+
argumentTypes.clear();
1712+
auto *fnTy = applicableFn->getFirstType()->castTo<FunctionType>();
1713+
ArgumentInfoCollector argInfo(*this, fnTy);
1714+
// Stop if we hit anything with concrete types or conformances to
1715+
// literals.
1716+
if (!argInfo.getTypes().empty() || !argInfo.getLiteralProtocols().empty()) {
1717+
foundApplicable = applicableFn;
1718+
break;
1719+
}
1720+
}
1721+
1722+
if (!foundApplicable)
1723+
return;
1724+
1725+
// FIXME: It would be good to avoid this redundancy.
1726+
auto *fnTy = foundApplicable->getFirstType()->castTo<FunctionType>();
1727+
ArgumentInfoCollector argInfo(*this, fnTy);
1728+
1729+
size_t nextType = 0;
1730+
for (auto argType : argInfo.getTypes()) {
1731+
auto *nominal = argType->getAnyNominal();
1732+
for (size_t i = nextType + 1; i < nominalTypes.size(); ++i) {
1733+
if (nominal == nominalTypes[i]) {
1734+
std::swap(nominalTypes[nextType], nominalTypes[i]);
1735+
++nextType;
1736+
break;
1737+
}
1738+
}
1739+
}
1740+
1741+
if (nextType + 1 >= nominalTypes.size())
1742+
return;
1743+
1744+
for (auto *protocol : argInfo.getLiteralProtocols()) {
1745+
auto defaultType = TC.getDefaultType(protocol, DC);
1746+
auto *nominal = defaultType->getAnyNominal();
1747+
for (size_t i = nextType + 1; i < nominalTypes.size(); ++i) {
1748+
if (nominal == nominalTypes[i]) {
1749+
std::swap(nominalTypes[nextType], nominalTypes[i]);
1750+
++nextType;
1751+
break;
1752+
}
1753+
}
1754+
}
1755+
}
1756+
16861757
void ConstraintSystem::partitionForDesignatedTypes(
16871758
ArrayRef<Constraint *> Choices, ConstraintMatchLoop forEachChoice,
16881759
PartitionAppendCallback appendPartition) {
16891760

1690-
auto designatedNominalTypes = getOperatorDesignatedNominalTypes(Choices[0]);
1691-
if (designatedNominalTypes.empty())
1761+
auto types = getOperatorDesignatedNominalTypes(Choices[0]);
1762+
if (types.empty())
16921763
return;
16931764

1765+
SmallVector<NominalTypeDecl *, 4> designatedNominalTypes(types.begin(),
1766+
types.end());
1767+
1768+
if (designatedNominalTypes.size() > 1)
1769+
sortDesignatedTypes(designatedNominalTypes, Choices[0]);
1770+
16941771
SmallVector<SmallVector<unsigned, 4>, 4> definedInDesignatedType;
16951772
SmallVector<SmallVector<unsigned, 4>, 4> definedInExtensionOfDesignatedType;
16961773

lib/Sema/ConstraintSystem.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3227,6 +3227,12 @@ class ConstraintSystem {
32273227
typedef std::function<void(SmallVectorImpl<unsigned> &options)>
32283228
PartitionAppendCallback;
32293229

3230+
// Attempt to sort nominalTypes based on what we can discover about
3231+
// calls into the overloads in the disjunction that bindOverload is
3232+
// a part of.
3233+
void sortDesignatedTypes(SmallVectorImpl<NominalTypeDecl *> &nominalTypes,
3234+
Constraint *bindOverload);
3235+
32303236
// Partition the choices in a disjunction based on those that match
32313237
// the designated types for the operator that the disjunction was
32323238
// formed for.

validation-test/Sema/type_checker_perf/fast/rdar17024694.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift -solver-expression-time-threshold=1
1+
// RUN: %target-typecheck-verify-swift -solver-expression-time-threshold=1 -swift-version 5 -solver-disable-shrink -disable-constraint-solver-performance-hacks -solver-enable-operator-designated-types
22
// REQUIRES: tools-release,no_asserts
33

44
_ = (2...100).reversed().filter({ $0 % 11 == 0 }).map {

0 commit comments

Comments
 (0)