|
15 | 15 | //===----------------------------------------------------------------------===// |
16 | 16 |
|
17 | 17 | #include "OpenedExistentials.h" |
| 18 | +#include "Relation.h" |
18 | 19 | #include "TypeChecker.h" |
19 | 20 | #include "swift/AST/ConformanceLookup.h" |
20 | 21 | #include "swift/AST/Decl.h" |
@@ -1935,93 +1936,113 @@ ConstraintSystem::selectDisjunction() { |
1935 | 1936 |
|
1936 | 1937 | // Pick the disjunction with the smallest number of favored, then active |
1937 | 1938 | // 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(); |
1943 | 1942 |
|
1944 | | - if (firstActive == 1 || secondActive == 1) |
1945 | | - return secondActive != 1; |
| 1943 | + if (firstActive == 1 || secondActive == 1) |
| 1944 | + return secondActive != 1; |
1946 | 1945 |
|
1947 | | - if (auto preference = isPreferable(*this, first, second)) |
1948 | | - return preference.value(); |
| 1946 | + if (auto preference = isPreferable(*this, first, second)) |
| 1947 | + return preference.value(); |
1949 | 1948 |
|
1950 | | - const auto &firstFavorings = favorings[first]; |
1951 | | - const auto &secondFavorings = favorings[second]; |
| 1949 | + const auto &firstFavorings = favorings[first]; |
| 1950 | + const auto &secondFavorings = favorings[second]; |
1952 | 1951 |
|
1953 | | - auto firstScore = firstFavorings.Score; |
1954 | | - auto secondScore = secondFavorings.Score; |
| 1952 | + auto firstScore = firstFavorings.Score; |
| 1953 | + auto secondScore = secondFavorings.Score; |
1955 | 1954 |
|
1956 | | - bool isFirstOperator = isOperatorDisjunction(first); |
1957 | | - bool isSecondOperator = isOperatorDisjunction(second); |
| 1955 | + bool isFirstOperator = isOperatorDisjunction(first); |
| 1956 | + bool isSecondOperator = isOperatorDisjunction(second); |
1958 | 1957 |
|
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 | + } |
1968 | 1967 |
|
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; |
1976 | 1975 |
|
1977 | | - if (isSecondOperator && secondFavorings.IsSpeculative) |
1978 | | - secondScore = 0; |
1979 | | - } |
| 1976 | + if (isSecondOperator && secondFavorings.IsSpeculative) |
| 1977 | + secondScore = 0; |
| 1978 | + } |
1980 | 1979 |
|
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; |
1987 | 1986 |
|
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 | + } |
2006 | 2005 |
|
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 | + } |
2019 | 2018 |
|
2020 | | - numFirstFavored = numFirstFavored ? numFirstFavored : firstActive; |
2021 | | - numSecondFavored = numSecondFavored ? numSecondFavored : secondActive; |
| 2019 | + numFirstFavored = numFirstFavored ? numFirstFavored : firstActive; |
| 2020 | + numSecondFavored = numSecondFavored ? numSecondFavored : secondActive; |
2022 | 2021 |
|
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); |
2025 | 2046 |
|
2026 | 2047 | if (bestDisjunction != disjunctions.end()) |
2027 | 2048 | return std::make_pair(*bestDisjunction, |
|
0 commit comments