Skip to content

Commit 0c7a407

Browse files
committed
Sema: Add debugging code to ConstraintSystem::selectDisjunction()
1 parent 8e5f7bc commit 0c7a407

File tree

1 file changed

+95
-74
lines changed

1 file changed

+95
-74
lines changed

lib/Sema/CSOptimizer.cpp

Lines changed: 95 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
//===----------------------------------------------------------------------===//
1616

1717
#include "OpenedExistentials.h"
18+
#include "Relation.h"
1819
#include "TypeChecker.h"
1920
#include "swift/AST/ConformanceLookup.h"
2021
#include "swift/AST/Decl.h"
@@ -1935,93 +1936,113 @@ ConstraintSystem::selectDisjunction() {
19351936

19361937
// Pick the disjunction with the smallest number of favored, then active
19371938
// choices.
1938-
auto bestDisjunction = std::min_element(
1939-
disjunctions.begin(), disjunctions.end(),
1940-
[&](Constraint *first, Constraint *second) -> bool {
1941-
unsigned firstActive = first->countActiveNestedConstraints();
1942-
unsigned secondActive = second->countActiveNestedConstraints();
1939+
auto predicate = [&](Constraint *first, Constraint *second) -> bool {
1940+
unsigned firstActive = first->countActiveNestedConstraints();
1941+
unsigned secondActive = second->countActiveNestedConstraints();
19431942

1944-
if (firstActive == 1 || secondActive == 1)
1945-
return secondActive != 1;
1943+
if (firstActive == 1 || secondActive == 1)
1944+
return secondActive != 1;
19461945

1947-
if (auto preference = isPreferable(*this, first, second))
1948-
return preference.value();
1946+
if (auto preference = isPreferable(*this, first, second))
1947+
return preference.value();
19491948

1950-
const auto &firstFavorings = favorings[first];
1951-
const auto &secondFavorings = favorings[second];
1949+
const auto &firstFavorings = favorings[first];
1950+
const auto &secondFavorings = favorings[second];
19521951

1953-
auto firstScore = firstFavorings.Score;
1954-
auto secondScore = secondFavorings.Score;
1952+
auto firstScore = firstFavorings.Score;
1953+
auto secondScore = secondFavorings.Score;
19551954

1956-
bool isFirstOperator = isOperatorDisjunction(first);
1957-
bool isSecondOperator = isOperatorDisjunction(second);
1955+
bool isFirstOperator = isOperatorDisjunction(first);
1956+
bool isSecondOperator = isOperatorDisjunction(second);
19581957

1959-
// Infix logical operators are usually not overloaded and don't
1960-
// form disjunctions, but when they do, let's prefer them over
1961-
// other operators when they have fewer choices because it helps
1962-
// to split operator chains.
1963-
if (isFirstOperator && isSecondOperator) {
1964-
if (isStandardInfixLogicalOperator(first) !=
1965-
isStandardInfixLogicalOperator(second))
1966-
return firstActive < secondActive;
1967-
}
1958+
// Infix logical operators are usually not overloaded and don't
1959+
// form disjunctions, but when they do, let's prefer them over
1960+
// other operators when they have fewer choices because it helps
1961+
// to split operator chains.
1962+
if (isFirstOperator && isSecondOperator) {
1963+
if (isStandardInfixLogicalOperator(first) !=
1964+
isStandardInfixLogicalOperator(second))
1965+
return firstActive < secondActive;
1966+
}
19681967

1969-
// Not all of the non-operator disjunctions are supported by the
1970-
// ranking algorithm, so to prevent eager selection of operators
1971-
// when nothing concrete is known about them, let's reset the score
1972-
// and compare purely based on number of choices.
1973-
if (isFirstOperator != isSecondOperator) {
1974-
if (isFirstOperator && firstFavorings.IsSpeculative)
1975-
firstScore = 0;
1968+
// Not all of the non-operator disjunctions are supported by the
1969+
// ranking algorithm, so to prevent eager selection of operators
1970+
// when nothing concrete is known about them, let's reset the score
1971+
// and compare purely based on number of choices.
1972+
if (isFirstOperator != isSecondOperator) {
1973+
if (isFirstOperator && firstFavorings.IsSpeculative)
1974+
firstScore = 0;
19761975

1977-
if (isSecondOperator && secondFavorings.IsSpeculative)
1978-
secondScore = 0;
1979-
}
1976+
if (isSecondOperator && secondFavorings.IsSpeculative)
1977+
secondScore = 0;
1978+
}
19801979

1981-
// Rank based on scores only if both disjunctions are supported.
1982-
if (firstScore && secondScore) {
1983-
// If both disjunctions have the same score they should be ranked
1984-
// based on number of favored/active choices.
1985-
if (*firstScore != *secondScore)
1986-
return *firstScore > *secondScore;
1980+
// Rank based on scores only if both disjunctions are supported.
1981+
if (firstScore && secondScore) {
1982+
// If both disjunctions have the same score they should be ranked
1983+
// based on number of favored/active choices.
1984+
if (*firstScore != *secondScore)
1985+
return *firstScore > *secondScore;
19871986

1988-
// If the scores are the same and both disjunctions are operators
1989-
// they could be ranked purely based on whether the candidates
1990-
// were speculative or not. The one with more context always wins.
1991-
//
1992-
// Consider the following situation:
1993-
//
1994-
// func test(_: Int) { ... }
1995-
// func test(_: String) { ... }
1996-
//
1997-
// test("a" + "b" + "c")
1998-
//
1999-
// In this case we should always prefer ... + "c" over "a" + "b"
2000-
// because it would fail and prune the other overload if parameter
2001-
// type (aka contextual type) is `Int`.
2002-
if (isFirstOperator && isSecondOperator &&
2003-
firstFavorings.IsSpeculative != secondFavorings.IsSpeculative)
2004-
return secondFavorings.IsSpeculative;
2005-
}
1987+
// If the scores are the same and both disjunctions are operators
1988+
// they could be ranked purely based on whether the candidates
1989+
// were speculative or not. The one with more context always wins.
1990+
//
1991+
// Consider the following situation:
1992+
//
1993+
// func test(_: Int) { ... }
1994+
// func test(_: String) { ... }
1995+
//
1996+
// test("a" + "b" + "c")
1997+
//
1998+
// In this case we should always prefer ... + "c" over "a" + "b"
1999+
// because it would fail and prune the other overload if parameter
2000+
// type (aka contextual type) is `Int`.
2001+
if (isFirstOperator && isSecondOperator &&
2002+
firstFavorings.IsSpeculative != secondFavorings.IsSpeculative)
2003+
return secondFavorings.IsSpeculative;
2004+
}
20062005

2007-
// Use favored choices only if disjunction score is higher
2008-
// than zero. This means that we can maintain favoring
2009-
// choices without impacting selection decisions.
2010-
unsigned numFirstFavored =
2011-
firstScore.value_or(0) ? firstFavorings.FavoredChoices.size() : 0;
2012-
unsigned numSecondFavored =
2013-
secondScore.value_or(0) ? secondFavorings.FavoredChoices.size() : 0;
2014-
2015-
if (numFirstFavored == numSecondFavored) {
2016-
if (firstActive != secondActive)
2017-
return firstActive < secondActive;
2018-
}
2006+
// Use favored choices only if disjunction score is higher
2007+
// than zero. This means that we can maintain favoring
2008+
// choices without impacting selection decisions.
2009+
unsigned numFirstFavored =
2010+
firstScore.value_or(0) ? firstFavorings.FavoredChoices.size() : 0;
2011+
unsigned numSecondFavored =
2012+
secondScore.value_or(0) ? secondFavorings.FavoredChoices.size() : 0;
2013+
2014+
if (numFirstFavored == numSecondFavored) {
2015+
if (firstActive != secondActive)
2016+
return firstActive < secondActive;
2017+
}
20192018

2020-
numFirstFavored = numFirstFavored ? numFirstFavored : firstActive;
2021-
numSecondFavored = numSecondFavored ? numSecondFavored : secondActive;
2019+
numFirstFavored = numFirstFavored ? numFirstFavored : firstActive;
2020+
numSecondFavored = numSecondFavored ? numSecondFavored : secondActive;
20222021

2023-
return numFirstFavored < numSecondFavored;
2024-
});
2022+
return numFirstFavored < numSecondFavored;
2023+
};
2024+
2025+
static bool verifyDisjunctionOrder = false;
2026+
2027+
if (verifyDisjunctionOrder) {
2028+
auto matrix = BooleanMatrix::forPredicate(
2029+
disjunctions.begin(), disjunctions.end(),
2030+
predicate);
2031+
if (!matrix.isAntiReflexive()) {
2032+
llvm::errs() << "Broken disjunction order: not anti-reflexive\n";
2033+
matrix.dump(llvm::errs());
2034+
abort();
2035+
}
2036+
if (!matrix.isTransitive()) {
2037+
llvm::errs() << "Broken disjunction order: not transitive\n";
2038+
matrix.dump(llvm::errs());
2039+
abort();
2040+
}
2041+
}
2042+
2043+
auto bestDisjunction = std::min_element(
2044+
disjunctions.begin(), disjunctions.end(),
2045+
predicate);
20252046

20262047
if (bestDisjunction != disjunctions.end())
20272048
return std::make_pair(*bestDisjunction,

0 commit comments

Comments
 (0)