Skip to content

Commit b14c803

Browse files
authored
Merge pull request #11519 from xedin/unavailable-limits-perf-hacks
[ConstraintSolver] Skip performance hacks in presence of unavailable …
2 parents b0e0f67 + 47353c2 commit b14c803

File tree

3 files changed

+88
-35
lines changed

3 files changed

+88
-35
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7155,11 +7155,22 @@ bool FailureDiagnosis::visitInOutExpr(InOutExpr *IOE) {
71557155

71567156
bool FailureDiagnosis::visitCoerceExpr(CoerceExpr *CE) {
71577157
// Coerce the input to whatever type is specified by the CoerceExpr.
7158-
if (!typeCheckChildIndependently(CE->getSubExpr(),
7159-
CE->getCastTypeLoc().getType(),
7160-
CTP_CoerceOperand))
7158+
auto expr = typeCheckChildIndependently(CE->getSubExpr(),
7159+
CE->getCastTypeLoc().getType(),
7160+
CTP_CoerceOperand);
7161+
if (!expr)
71617162
return true;
71627163

7164+
auto ref = expr->getReferencedDecl();
7165+
if (auto *decl = ref.getDecl()) {
7166+
// Without explicit coercion we might end up
7167+
// type-checking sub-expression as unavaible
7168+
// declaration, let's try to diagnose that here.
7169+
if (AvailableAttr::isUnavailable(decl))
7170+
return CS.TC.diagnoseExplicitUnavailability(
7171+
decl, expr->getSourceRange(), CS.DC, dyn_cast<ApplyExpr>(expr));
7172+
}
7173+
71637174
return false;
71647175
}
71657176

lib/Sema/CSSolver.cpp

Lines changed: 68 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1706,6 +1706,44 @@ void ConstraintSystem::collectDisjunctions(
17061706
}
17071707
}
17081708

1709+
/// \brief Check if the given disjunction choice should be attempted by solver.
1710+
static bool shouldSkipDisjunctionChoice(ConstraintSystem &cs,
1711+
DisjunctionChoice &choice,
1712+
Optional<Score> &bestNonGenericScore) {
1713+
if (choice->isDisabled()) {
1714+
auto &TC = cs.TC;
1715+
if (TC.getLangOpts().DebugConstraintSolver) {
1716+
auto &log = cs.getASTContext().TypeCheckerDebug->getStream();
1717+
log.indent(cs.solverState->depth)
1718+
<< "(skipping ";
1719+
choice->print(log, &TC.Context.SourceMgr);
1720+
log << '\n';
1721+
}
1722+
1723+
return true;
1724+
}
1725+
1726+
// Don't attempt to solve for generic operators if we already have
1727+
// a non-generic solution.
1728+
1729+
// FIXME: Less-horrible but still horrible hack to attempt to
1730+
// speed things up. Skip the generic operators if we
1731+
// already have a solution involving non-generic operators,
1732+
// but continue looking for a better non-generic operator
1733+
// solution.
1734+
if (bestNonGenericScore && choice.isGenericOperatorOrUnavailable()) {
1735+
auto &score = bestNonGenericScore->Data;
1736+
// Let's skip generic overload choices only in case if
1737+
// non-generic score indicates that there were no forced
1738+
// unwrappings of optional(s) and no unavailable overload
1739+
// choices present in the solution.
1740+
if (score[SK_ForceUnchecked] == 0 && score[SK_Unavailable] == 0)
1741+
return true;
1742+
}
1743+
1744+
return false;
1745+
}
1746+
17091747
bool ConstraintSystem::solveSimplified(
17101748
SmallVectorImpl<Solution> &solutions,
17111749
FreeTypeVariableBinding allowFreeTypeVariables) {
@@ -1789,47 +1827,29 @@ bool ConstraintSystem::solveSimplified(
17891827
auto afterDisjunction = InactiveConstraints.erase(disjunction);
17901828
CG.removeConstraint(disjunction);
17911829

1792-
Score initialScore = CurrentScore;
1793-
Optional<DisjunctionChoice> lastSolvedChoice;
1830+
Optional<std::pair<DisjunctionChoice, Score>> lastSolvedChoice;
17941831
Optional<Score> bestNonGenericScore;
17951832

17961833
++solverState->NumDisjunctions;
17971834
auto constraints = disjunction->getNestedConstraints();
17981835
// Try each of the constraints within the disjunction.
17991836
for (auto index : indices(constraints)) {
18001837
auto currentChoice = DisjunctionChoice(this, constraints[index]);
1801-
if (currentChoice.isDisabled()) {
1802-
if (TC.getLangOpts().DebugConstraintSolver) {
1803-
auto &log = getASTContext().TypeCheckerDebug->getStream();
1804-
log.indent(solverState->depth)
1805-
<< "(skipping ";
1806-
currentChoice->print(log, &TC.Context.SourceMgr);
1807-
log << '\n';
1808-
}
1838+
if (shouldSkipDisjunctionChoice(*this, currentChoice, bestNonGenericScore))
18091839
continue;
1810-
}
1811-
1812-
// Don't attempt to solve for generic operators if we already have
1813-
// a non-generic solution.
1814-
1815-
// FIXME: Less-horrible but still horrible hack to attempt to
1816-
// speed things up. Skip the generic operators if we
1817-
// already have a solution involving non-generic operators,
1818-
// but continue looking for a better non-generic operator
1819-
// solution.
1820-
if (bestNonGenericScore && currentChoice.isGenericOperatorOrUnavailable()) {
1821-
// If non-generic solution increased the score by applying any
1822-
// fixes or restrictions to the solution, let's not skip generic
1823-
// overloads because they could produce a better solution.
1824-
if (bestNonGenericScore <= initialScore)
1825-
continue;
1826-
}
18271840

18281841
// We already have a solution; check whether we should
18291842
// short-circuit the disjunction.
18301843
if (lastSolvedChoice) {
1831-
auto *lastChoice = lastSolvedChoice->getConstraint();
1832-
if (shortCircuitDisjunctionAt(&currentChoice, lastChoice,
1844+
auto *lastChoice = lastSolvedChoice->first.getConstraint();
1845+
auto &score = lastSolvedChoice->second;
1846+
bool hasUnavailableOverloads = score.Data[SK_Unavailable] > 0;
1847+
1848+
// Attempt to short-circuit disjunction only if
1849+
// score indicates that there are no unavailable
1850+
// overload choices present in the solution.
1851+
if (!hasUnavailableOverloads &&
1852+
shortCircuitDisjunctionAt(&currentChoice, lastChoice,
18331853
getASTContext()))
18341854
break;
18351855
}
@@ -1864,7 +1884,7 @@ bool ConstraintSystem::solveSimplified(
18641884
bestNonGenericScore = score;
18651885
}
18661886

1867-
lastSolvedChoice = currentChoice;
1887+
lastSolvedChoice = {currentChoice, *score};
18681888

18691889
// If we see a tuple-to-tuple conversion that succeeded, we're done.
18701890
// FIXME: This should be more general.
@@ -1894,8 +1914,24 @@ Optional<Score>
18941914
DisjunctionChoice::solve(SmallVectorImpl<Solution> &solutions,
18951915
FreeTypeVariableBinding allowFreeTypeVariables) {
18961916
CS->simplifyDisjunctionChoice(Choice);
1897-
bool failed = CS->solveRec(solutions, allowFreeTypeVariables);
1898-
return failed ? None : Optional<Score>(CS->CurrentScore);
1917+
1918+
if (CS->solveRec(solutions, allowFreeTypeVariables))
1919+
return None;
1920+
1921+
assert (!solutions.empty());
1922+
1923+
Score bestScore = solutions.front().getFixedScore();
1924+
1925+
if (solutions.size() == 1)
1926+
return bestScore;
1927+
1928+
for (unsigned i = 1, n = solutions.size(); i != n; ++i) {
1929+
auto &score = solutions[i].getFixedScore();
1930+
if (score < bestScore)
1931+
bestScore = score;
1932+
}
1933+
1934+
return bestScore;
18991935
}
19001936

19011937
bool DisjunctionChoice::isGenericOperatorOrUnavailable() const {

test/Constraints/diagnostics_swift4.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,9 @@ class R<K: Hashable, V> {
4949
dict.forEach(body)
5050
}
5151
}
52+
53+
// Make sure that solver doesn't try to form solutions with available overloads when better generic choices are present.
54+
infix operator +=+ : AdditionPrecedence
55+
func +=+(_ lhs: Int, _ rhs: Int) -> Bool { return lhs == rhs }
56+
func +=+<T: BinaryInteger>(_ lhs: T, _ rhs: Int) -> Bool { return lhs == rhs }
57+
let _ = DoubleWidth<Int>(Int.min) - 1 +=+ Int.min // Ok

0 commit comments

Comments
 (0)