Skip to content

Commit b158651

Browse files
committed
[ConstraintSystem] Extend solver support for designated types for operators.
Have the constraint solver consider multiple designated types for an operator. We currently consider the overloads from each in turn, stopping as soon as we have a solution. As a result, we can still end up with exponential type checking in some cases if an operator has more than a single designated type. This still allows us to reduce the base of that exponent, though, which makes it possible to increase the number of expressions we can type check successfully in practice.
1 parent a1a747c commit b158651

File tree

3 files changed

+58
-34
lines changed

3 files changed

+58
-34
lines changed

lib/Sema/CSSolver.cpp

Lines changed: 52 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1629,13 +1629,12 @@ static bool isOperatorBindOverload(Constraint *bindOverload) {
16291629
// Given a bind overload constraint for an operator, return the
16301630
// protocol designated as the first place to look for overloads of the
16311631
// operator.
1632-
static NominalTypeDecl *
1633-
getOperatorDesignatedNominalType(Constraint *bindOverload) {
1632+
static ArrayRef<NominalTypeDecl *>
1633+
getOperatorDesignatedNominalTypes(Constraint *bindOverload) {
16341634
auto choice = bindOverload->getOverloadChoice();
16351635
auto *funcDecl = cast<FuncDecl>(choice.getDecl());
16361636
auto *operatorDecl = funcDecl->getOperatorDecl();
1637-
auto designatedTypes = operatorDecl->getDesignatedNominalTypes();
1638-
return !designatedTypes.empty() ? designatedTypes[0] : nullptr;
1637+
return operatorDecl->getDesignatedNominalTypes();
16391638
}
16401639

16411640
void ConstraintSystem::partitionDisjunction(
@@ -1660,8 +1659,8 @@ void ConstraintSystem::partitionDisjunction(
16601659
SmallVector<unsigned, 4> disabled;
16611660
SmallVector<unsigned, 4> unavailable;
16621661
SmallVector<unsigned, 4> globalScope;
1663-
SmallVector<unsigned, 4> definedInDesignatedType;
1664-
SmallVector<unsigned, 4> definedInExtensionOfDesignatedType;
1662+
SmallVector<SmallVector<unsigned, 4>, 4> definedInDesignatedType;
1663+
SmallVector<SmallVector<unsigned, 4>, 4> definedInExtensionOfDesignatedType;
16651664
SmallVector<unsigned, 4> everythingElse;
16661665
SmallSet<Constraint *, 16> taken;
16671666

@@ -1722,28 +1721,43 @@ void ConstraintSystem::partitionDisjunction(
17221721

17231722
// Now collect the overload choices that are defined within the type
17241723
// that was designated in the operator declaration.
1725-
auto *designatedNominal = getOperatorDesignatedNominalType(Choices[0]);
1726-
if (designatedNominal) {
1727-
forEachChoice(Choices, [&](unsigned index, Constraint *constraint) -> bool {
1728-
auto *decl = constraint->getOverloadChoice().getDecl();
1729-
auto *funcDecl = cast<FuncDecl>(decl);
1730-
1731-
auto *parentDecl = funcDecl->getParent()->getAsDecl();
1732-
if (parentDecl == designatedNominal) {
1733-
definedInDesignatedType.push_back(index);
1734-
return true;
1735-
}
1724+
auto designatedNominalTypes = getOperatorDesignatedNominalTypes(Choices[0]);
1725+
if (!designatedNominalTypes.empty()) {
1726+
forEachChoice(
1727+
Choices, [&](unsigned constraintIndex, Constraint *constraint) -> bool {
1728+
auto *decl = constraint->getOverloadChoice().getDecl();
1729+
auto *funcDecl = cast<FuncDecl>(decl);
1730+
1731+
auto *parentDecl = funcDecl->getParent()->getAsDecl();
1732+
for (auto designatedTypeIndex : indices(designatedNominalTypes)) {
1733+
auto *designatedNominal =
1734+
designatedNominalTypes[designatedTypeIndex];
1735+
if (parentDecl == designatedNominal) {
1736+
if (designatedTypeIndex >= definedInDesignatedType.size())
1737+
definedInDesignatedType.resize(designatedTypeIndex + 1);
1738+
auto &constraints = definedInDesignatedType[designatedTypeIndex];
1739+
constraints.push_back(constraintIndex);
1740+
return true;
1741+
}
17361742

1737-
if (auto *extensionDecl = dyn_cast<ExtensionDecl>(parentDecl)) {
1738-
parentDecl = extensionDecl->getExtendedNominal();
1739-
if (parentDecl == designatedNominal) {
1740-
definedInExtensionOfDesignatedType.push_back(index);
1741-
return true;
1743+
if (auto *extensionDecl = dyn_cast<ExtensionDecl>(parentDecl)) {
1744+
parentDecl = extensionDecl->getExtendedNominal();
1745+
if (parentDecl == designatedNominal) {
1746+
if (designatedTypeIndex >=
1747+
definedInExtensionOfDesignatedType.size())
1748+
definedInExtensionOfDesignatedType.resize(
1749+
designatedTypeIndex + 1);
1750+
1751+
auto &constraints =
1752+
definedInExtensionOfDesignatedType[designatedTypeIndex];
1753+
constraints.push_back(constraintIndex);
1754+
return true;
1755+
}
1756+
}
17421757
}
1743-
}
17441758

1745-
return false;
1746-
});
1759+
return false;
1760+
});
17471761
}
17481762

17491763
// Gather the remaining options.
@@ -1762,8 +1776,19 @@ void ConstraintSystem::partitionDisjunction(
17621776
};
17631777

17641778
// Now create the partitioning based on what was collected.
1765-
appendPartition(definedInDesignatedType);
1766-
appendPartition(definedInExtensionOfDesignatedType);
1779+
1780+
// First we'll add partitions for each of the overloads we found in
1781+
// types that were designated as part of the operator declaration.
1782+
for (auto designatedTypeIndex : indices(designatedNominalTypes)) {
1783+
if (designatedTypeIndex < definedInDesignatedType.size()) {
1784+
auto &primary = definedInDesignatedType[designatedTypeIndex];
1785+
appendPartition(primary);
1786+
}
1787+
if (designatedTypeIndex < definedInExtensionOfDesignatedType.size()) {
1788+
auto &secondary = definedInExtensionOfDesignatedType[designatedTypeIndex];
1789+
appendPartition(secondary);
1790+
}
1791+
}
17671792
appendPartition(everythingElse);
17681793
appendPartition(globalScope);
17691794
appendPartition(unavailable);

stdlib/public/core/Policy.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -422,15 +422,15 @@ infix operator &>> : BitwiseShiftPrecedence, FixedWidthInteger
422422

423423
infix operator * : MultiplicationPrecedence, Numeric
424424
infix operator &* : MultiplicationPrecedence, FixedWidthInteger
425-
infix operator / : MultiplicationPrecedence, BinaryInteger
425+
infix operator / : MultiplicationPrecedence, BinaryInteger, FloatingPoint
426426
infix operator % : MultiplicationPrecedence, BinaryInteger
427427
infix operator & : MultiplicationPrecedence, BinaryInteger
428428

429429
// "Additive"
430430

431-
infix operator + : AdditionPrecedence, Numeric
431+
infix operator + : AdditionPrecedence, Numeric, String, Strideable
432432
infix operator &+ : AdditionPrecedence, FixedWidthInteger
433-
infix operator - : AdditionPrecedence, Numeric
433+
infix operator - : AdditionPrecedence, Numeric, Strideable
434434
infix operator &- : AdditionPrecedence, FixedWidthInteger
435435
infix operator | : AdditionPrecedence, BinaryInteger
436436
infix operator ^ : AdditionPrecedence, BinaryInteger
@@ -482,9 +482,9 @@ infix operator *= : AssignmentPrecedence, Numeric
482482
infix operator &*= : AssignmentPrecedence, FixedWidthInteger
483483
infix operator /= : AssignmentPrecedence, BinaryInteger
484484
infix operator %= : AssignmentPrecedence, BinaryInteger
485-
infix operator += : AssignmentPrecedence, Numeric
485+
infix operator += : AssignmentPrecedence, Numeric, String, Strideable
486486
infix operator &+= : AssignmentPrecedence, FixedWidthInteger
487-
infix operator -= : AssignmentPrecedence, Numeric
487+
infix operator -= : AssignmentPrecedence, Numeric, Strideable
488488
infix operator &-= : AssignmentPrecedence, FixedWidthInteger
489489
infix operator <<= : AssignmentPrecedence, BinaryInteger
490490
infix operator &<<= : AssignmentPrecedence, FixedWidthInteger
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
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
let i: Int? = 1
55
let j: Int?
66
let k: Int? = 2
77

88
let _ = [i, j, k].reduce(0 as Int?) {
9-
// expected-error@-1 {{reasonable time}}
109
$0 != nil && $1 != nil ? $0! + $1! : ($0 != nil ? $0! : ($1 != nil ? $1! : nil))
1110
}

0 commit comments

Comments
 (0)