Skip to content

Commit da040d0

Browse files
committed
Revert "[CSOptimizer] Initial implementation of disjunction choice favoring algorithm"
This reverts commit 672ae3d.
1 parent d3f9541 commit da040d0

File tree

10 files changed

+125
-415
lines changed

10 files changed

+125
-415
lines changed

lib/Sema/CSOptimizer.cpp

Lines changed: 2 additions & 410 deletions
Large diffs are not rendered by default.

lib/Sema/CSSolver.cpp

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,6 +1285,62 @@ ConstraintSystem::filterDisjunction(
12851285
return SolutionKind::Unsolved;
12861286
}
12871287

1288+
// Attempt to find a disjunction of bind constraints where all options
1289+
// in the disjunction are binding the same type variable.
1290+
//
1291+
// Prefer disjunctions where the bound type variable is also the
1292+
// right-hand side of a conversion constraint, since having a concrete
1293+
// type that we're converting to can make it possible to split the
1294+
// constraint system into multiple ones.
1295+
static Constraint *selectBestBindingDisjunction(
1296+
ConstraintSystem &cs, SmallVectorImpl<Constraint *> &disjunctions) {
1297+
1298+
if (disjunctions.empty())
1299+
return nullptr;
1300+
1301+
auto getAsTypeVar = [&cs](Type type) {
1302+
return cs.simplifyType(type)->getRValueType()->getAs<TypeVariableType>();
1303+
};
1304+
1305+
Constraint *firstBindDisjunction = nullptr;
1306+
for (auto *disjunction : disjunctions) {
1307+
auto choices = disjunction->getNestedConstraints();
1308+
assert(!choices.empty());
1309+
1310+
auto *choice = choices.front();
1311+
if (choice->getKind() != ConstraintKind::Bind)
1312+
continue;
1313+
1314+
// We can judge disjunction based on the single choice
1315+
// because all of choices (of bind overload set) should
1316+
// have the same left-hand side.
1317+
// Only do this for simple type variable bindings, not for
1318+
// bindings like: ($T1) -> $T2 bind String -> Int
1319+
auto *typeVar = getAsTypeVar(choice->getFirstType());
1320+
if (!typeVar)
1321+
continue;
1322+
1323+
if (!firstBindDisjunction)
1324+
firstBindDisjunction = disjunction;
1325+
1326+
auto constraints = cs.getConstraintGraph().gatherConstraints(
1327+
typeVar, ConstraintGraph::GatheringKind::EquivalenceClass,
1328+
[](Constraint *constraint) {
1329+
return constraint->getKind() == ConstraintKind::Conversion;
1330+
});
1331+
1332+
for (auto *constraint : constraints) {
1333+
if (typeVar == getAsTypeVar(constraint->getSecondType()))
1334+
return disjunction;
1335+
}
1336+
}
1337+
1338+
// If we had any binding disjunctions, return the first of
1339+
// those. These ensure that we attempt to bind types earlier than
1340+
// trying the elements of other disjunctions, which can often mean
1341+
// we fail faster.
1342+
return firstBindDisjunction;
1343+
}
12881344

12891345
std::optional<std::pair<Constraint *, unsigned>>
12901346
ConstraintSystem::findConstraintThroughOptionals(
@@ -1760,6 +1816,63 @@ void DisjunctionChoiceProducer::partitionDisjunction(
17601816
assert(Ordering.size() == Choices.size());
17611817
}
17621818

1819+
Constraint *ConstraintSystem::selectDisjunction() {
1820+
SmallVector<Constraint *, 4> disjunctions;
1821+
1822+
collectDisjunctions(disjunctions);
1823+
if (disjunctions.empty())
1824+
return nullptr;
1825+
1826+
optimizeDisjunctions(disjunctions);
1827+
1828+
if (auto *disjunction = selectBestBindingDisjunction(*this, disjunctions))
1829+
return disjunction;
1830+
1831+
// Pick the disjunction with the smallest number of favored, then active choices.
1832+
auto cs = this;
1833+
auto minDisjunction = std::min_element(disjunctions.begin(), disjunctions.end(),
1834+
[&](Constraint *first, Constraint *second) -> bool {
1835+
unsigned firstActive = first->countActiveNestedConstraints();
1836+
unsigned secondActive = second->countActiveNestedConstraints();
1837+
unsigned firstFavored = first->countFavoredNestedConstraints();
1838+
unsigned secondFavored = second->countFavoredNestedConstraints();
1839+
1840+
if (!isOperatorDisjunction(first) || !isOperatorDisjunction(second))
1841+
return firstActive < secondActive;
1842+
1843+
if (firstFavored == secondFavored) {
1844+
// Look for additional choices that are "favored"
1845+
SmallVector<unsigned, 4> firstExisting;
1846+
SmallVector<unsigned, 4> secondExisting;
1847+
1848+
existingOperatorBindingsForDisjunction(*cs, first->getNestedConstraints(), firstExisting);
1849+
firstFavored += firstExisting.size();
1850+
existingOperatorBindingsForDisjunction(*cs, second->getNestedConstraints(), secondExisting);
1851+
secondFavored += secondExisting.size();
1852+
}
1853+
1854+
// Everything else equal, choose the disjunction with the greatest
1855+
// number of resolved argument types. The number of resolved argument
1856+
// types is always zero for disjunctions that don't represent applied
1857+
// overloads.
1858+
if (firstFavored == secondFavored) {
1859+
if (firstActive != secondActive)
1860+
return firstActive < secondActive;
1861+
1862+
return (first->countResolvedArgumentTypes(*this) > second->countResolvedArgumentTypes(*this));
1863+
}
1864+
1865+
firstFavored = firstFavored ? firstFavored : firstActive;
1866+
secondFavored = secondFavored ? secondFavored : secondActive;
1867+
return firstFavored < secondFavored;
1868+
});
1869+
1870+
if (minDisjunction != disjunctions.end())
1871+
return *minDisjunction;
1872+
1873+
return nullptr;
1874+
}
1875+
17631876
Constraint *ConstraintSystem::selectConjunction() {
17641877
SmallVector<Constraint *, 4> conjunctions;
17651878
for (auto &constraint : InactiveConstraints) {

test/Constraints/common_type.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
// RUN: %target-typecheck-verify-swift -debug-constraints 2>%t.err
22
// RUN: %FileCheck %s < %t.err
33

4-
// REQUIRES: needs_adjustment_for_new_favoring
5-
64
struct X {
75
func g(_: Int) -> Int { return 0 }
86
func g(_: Double) -> Int { return 0 }

test/Constraints/diag_ambiguities.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ C(g) // expected-error{{ambiguous use of 'g'}}
2929
func h<T>(_ x: T) -> () {}
3030
_ = C(h) // OK - init(_: (Int) -> ())
3131

32-
func rdar29691909_callee(_ o: AnyObject?) -> Any? { return o }
33-
func rdar29691909_callee(_ o: AnyObject) -> Any { return o }
32+
func rdar29691909_callee(_ o: AnyObject?) -> Any? { return o } // expected-note {{found this candidate}}
33+
func rdar29691909_callee(_ o: AnyObject) -> Any { return o } // expected-note {{found this candidate}}
3434

3535
func rdar29691909(o: AnyObject) -> Any? {
36-
return rdar29691909_callee(o)
36+
return rdar29691909_callee(o) // expected-error{{ambiguous use of 'rdar29691909_callee'}}
3737
}
3838

3939
func rdar29907555(_ value: Any!) -> String {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// REQUIRES: tools-release,no_asan
33

44
func test(n: Int) -> Int {
5+
// expected-error@+1 {{the compiler is unable to type-check this expression in reasonable time}}
56
return n == 0 ? 0 : (0..<n).reduce(0) {
67
($0 > 0 && $1 % 2 == 0) ? ((($0 + $1) - ($0 + $1)) / ($1 - $0)) + (($0 + $1) / ($1 - $0)) : $0
78
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ func memoize<T: Hashable, U>( body: @escaping ((T)->U, T)->U ) -> (T)->U {
1414
}
1515

1616
let fibonacci = memoize {
17+
// expected-error@-1 {{reasonable time}}
1718
fibonacci, n in
1819
n < 2 ? Double(n) : fibonacci(n - 1) + fibonacci(n - 2)
1920
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33

44
func rdar31742586() -> Double {
55
return -(1 + 2) + -(3 + 4) + 5 - (-(1 + 2) + -(3 + 4) + 5)
6+
// expected-error@-1 {{the compiler is unable to type-check this expression in reasonable time}}
67
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,6 @@
33

44
func test() {
55
let _: UInt = 1 * 2 + 3 * 4 + 5 * 6 + 7 * 8 + 9 * 10 + 11 * 12 + 13 * 14
6+
// expected-error@-1 {{the compiler is unable to type-check this expression in reasonable time}}
67
}
8+

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ func wrap<T: ExpressibleByStringLiteral>(_ key: String, _ value: T) -> T { retur
88

99
func wrapped() -> Int {
1010
return wrap("1", 1) + wrap("1", 1) + wrap("1", 1) + wrap("1", 1) + wrap("1", 1) + wrap("1", 1)
11+
// expected-error@-1 {{the compiler is unable to type-check this expression in reasonable time}}
1112
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ func test() {
99
compute {
1010
print(x)
1111
let v: UInt64 = UInt64((24 / UInt32(1)) + UInt32(0) - UInt32(0) - 24 / 42 - 42)
12+
// expected-error@-1 {{the compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions}}
1213
print(v)
1314
}
1415
}

0 commit comments

Comments
 (0)