Skip to content

Commit 35f3f71

Browse files
authored
Merge pull request #4492 from apple/revert-4485-dpc
Revert "[Type checker] Introduce directional path consistency algorithm"
2 parents f683d84 + a84704f commit 35f3f71

File tree

6 files changed

+43
-552
lines changed

6 files changed

+43
-552
lines changed

include/swift/AST/Expr.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,11 +1415,7 @@ class OverloadSetRefExpr : public Expr {
14151415

14161416
public:
14171417
ArrayRef<ValueDecl*> getDecls() const { return Decls; }
1418-
1419-
void setDecls(ArrayRef<ValueDecl *> domain) {
1420-
Decls = domain;
1421-
}
1422-
1418+
14231419
/// getBaseType - Determine the type of the base object provided for the
14241420
/// given overload set, which is only non-null when dealing with an overloaded
14251421
/// member reference.

lib/Sema/CSSolver.cpp

Lines changed: 1 addition & 318 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@
2020
#include "llvm/Support/SaveAndRestore.h"
2121
#include <memory>
2222
#include <tuple>
23-
#include <stack>
24-
#include <queue>
2523
using namespace swift;
2624
using namespace constraints;
2725

@@ -1335,321 +1333,6 @@ ConstraintSystem::solveSingle(FreeTypeVariableBinding allowFreeTypeVariables) {
13351333
return std::move(solutions[0]);
13361334
}
13371335

1338-
bool ConstraintSystem::Candidate::solve() {
1339-
// Cleanup after constraint system generation/solving,
1340-
// because it would assign types to expressions, which
1341-
// might interfere with solving higher-level expressions.
1342-
ExprCleaner cleaner(E);
1343-
1344-
// Allocate new constraint system for sub-expression.
1345-
ConstraintSystem cs(TC, DC, None);
1346-
1347-
// Set contextual type if present. This is done before constraint generation
1348-
// to give a "hint" to that operation about possible optimizations.
1349-
if (!CT.isNull())
1350-
cs.setContextualType(E, CT, CTP);
1351-
1352-
// Generate constraints for the new system.
1353-
if (auto generatedExpr = cs.generateConstraints(E)) {
1354-
E = generatedExpr;
1355-
} else {
1356-
// Failure to generate constraint system for sub-expression means we can't
1357-
// continue solving sub-expressions.
1358-
return true;
1359-
}
1360-
1361-
// If there is contextual type present, add an explicit "conversion"
1362-
// constraint to the system.
1363-
if (!CT.isNull()) {
1364-
auto constraintKind = ConstraintKind::Conversion;
1365-
if (CTP == CTP_CallArgument)
1366-
constraintKind = ConstraintKind::ArgumentConversion;
1367-
1368-
cs.addConstraint(constraintKind, E->getType(), CT.getType(),
1369-
cs.getConstraintLocator(E), /*isFavored=*/true);
1370-
}
1371-
1372-
// Try to solve the system and record all available solutions.
1373-
llvm::SmallVector<Solution, 2> solutions;
1374-
{
1375-
SolverState state(cs);
1376-
cs.solverState = &state;
1377-
1378-
// Use solveRec() instead of solve() in here, because solve()
1379-
// would try to deduce the best solution, which we don't
1380-
// really want. Instead, we want the reduced set of domain choices.
1381-
cs.solveRec(solutions, FreeTypeVariableBinding::Allow);
1382-
1383-
cs.solverState = nullptr;
1384-
}
1385-
1386-
// No solutions for the sub-expression means that either main expression
1387-
// needs salvaging or it's inconsistent (read: doesn't have solutions).
1388-
if (solutions.empty())
1389-
return true;
1390-
1391-
// Record found solutions as suggestions.
1392-
this->applySolutions(solutions);
1393-
return false;
1394-
}
1395-
1396-
void ConstraintSystem::Candidate::applySolutions(
1397-
llvm::SmallVectorImpl<Solution> &solutions) const {
1398-
// A collection of OSRs with their newly reduced domains,
1399-
// it's domains are sets because multiple solutions can have the same
1400-
// choice for one of the type variables, and we want no duplication.
1401-
llvm::SmallDenseMap<OverloadSetRefExpr *, llvm::SmallSet<ValueDecl *, 2>>
1402-
domains;
1403-
for (auto &solution : solutions) {
1404-
for (auto choice : solution.overloadChoices) {
1405-
// Some of the choices might not have locators.
1406-
if (!choice.getFirst())
1407-
continue;
1408-
1409-
auto anchor = choice.getFirst()->getAnchor();
1410-
// Anchor is not available or expression is not an overload set.
1411-
if (!anchor || !isa<OverloadSetRefExpr>(anchor))
1412-
continue;
1413-
1414-
auto OSR = cast<OverloadSetRefExpr>(anchor);
1415-
auto overload = choice.getSecond().choice;
1416-
auto type = overload.getDecl()->getInterfaceType();
1417-
1418-
// One of the solutions has polymorphic type assigned with one of it's
1419-
// type variables. Such functions can only be properly resolved
1420-
// via complete expression, so we'll have to forget solutions
1421-
// we have already recorded. They might not include all viable overload
1422-
// choices.
1423-
if (type->is<GenericFunctionType>()) {
1424-
return;
1425-
}
1426-
1427-
domains[OSR].insert(overload.getDecl());
1428-
}
1429-
}
1430-
1431-
// Reduce the domains.
1432-
for (auto &domain : domains) {
1433-
auto OSR = domain.getFirst();
1434-
auto &choices = domain.getSecond();
1435-
1436-
// If the domain wasn't reduced, skip it.
1437-
if (OSR->getDecls().size() == choices.size()) continue;
1438-
1439-
// Update the expression with the reduced domain.
1440-
MutableArrayRef<ValueDecl *> decls
1441-
= TC.Context.AllocateUninitialized<ValueDecl *>(choices.size());
1442-
std::uninitialized_copy(choices.begin(), choices.end(), decls.begin());
1443-
OSR->setDecls(decls);
1444-
}
1445-
}
1446-
1447-
void ConstraintSystem::shrink(Expr *expr) {
1448-
typedef llvm::SmallDenseMap<Expr *, ArrayRef<ValueDecl *>> DomainMap;
1449-
1450-
// A collection of original domains of all of the expressions,
1451-
// so they can be restored in case of failure.
1452-
DomainMap domains;
1453-
1454-
struct ExprCollector : public ASTWalker {
1455-
// The primary constraint system.
1456-
ConstraintSystem &CS;
1457-
1458-
// All of the sub-expressions of certain type (binary/unary/calls) in
1459-
// depth-first order.
1460-
std::queue<Candidate> &SubExprs;
1461-
1462-
// Counts the number of overload sets present in the tree so far.
1463-
// Note that the traversal is depth-first.
1464-
std::stack<std::pair<ApplyExpr *, unsigned>,
1465-
llvm::SmallVector<std::pair<ApplyExpr *, unsigned>, 4>>
1466-
ApplyExprs;
1467-
1468-
// A collection of original domains of all of the expressions,
1469-
// so they can be restored in case of failure.
1470-
DomainMap &Domains;
1471-
1472-
ExprCollector(ConstraintSystem &cs,
1473-
std::queue<Candidate> &container,
1474-
DomainMap &domains)
1475-
: CS(cs), SubExprs(container), Domains(domains) { }
1476-
1477-
std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
1478-
// A dictionary expression is just a set of tuples; try to solve ones
1479-
// that have overload sets.
1480-
if (auto dictionaryExpr = dyn_cast<DictionaryExpr>(expr)) {
1481-
for (auto element : dictionaryExpr->getElements()) {
1482-
unsigned numOverlaods = 0;
1483-
element->walk(OverloadSetCounter(numOverlaods));
1484-
1485-
// There are no overload sets in the element; skip it.
1486-
if (numOverlaods == 0)
1487-
continue;
1488-
1489-
// FIXME: Could we avoid creating a separate dictionary expression
1490-
// here by introducing a contextual type on the element?
1491-
auto dict = DictionaryExpr::create(CS.getASTContext(),
1492-
dictionaryExpr->getLBracketLoc(),
1493-
{ element },
1494-
dictionaryExpr->getRBracketLoc(),
1495-
dictionaryExpr->getType());
1496-
1497-
// Make each of the dictionary elements an independent dictionary,
1498-
// such makes it easy to type-check everything separately.
1499-
SubExprs.push(Candidate(CS, dict));
1500-
}
1501-
1502-
// Don't try to walk into the dictionary.
1503-
return { false, expr };
1504-
}
1505-
1506-
// Let's not attempt to type-check closures or default values,
1507-
// which has already been type checked anyway.
1508-
if (isa<ClosureExpr>(expr) || isa<DefaultValueExpr>(expr)) {
1509-
return { false, expr };
1510-
}
1511-
1512-
// Coerce to type expressions are only viable if they have
1513-
// a single child expression.
1514-
if (auto coerceExpr = dyn_cast<CoerceExpr>(expr)) {
1515-
if (!coerceExpr->getSubExpr()) {
1516-
return { false, expr };
1517-
}
1518-
}
1519-
1520-
if (auto OSR = dyn_cast<OverloadSetRefExpr>(expr)) {
1521-
Domains[OSR] = OSR->getDecls();
1522-
}
1523-
1524-
if (auto applyExpr = dyn_cast<ApplyExpr>(expr)) {
1525-
auto func = applyExpr->getFn();
1526-
// Let's record this function application for post-processing
1527-
// as well as if it contains overload set, see walkToExprPost.
1528-
ApplyExprs.push({ applyExpr, isa<OverloadSetRefExpr>(func) });
1529-
}
1530-
1531-
return { true, expr };
1532-
}
1533-
1534-
Expr *walkToExprPost(Expr *expr) override {
1535-
if (!isa<ApplyExpr>(expr))
1536-
return expr;
1537-
1538-
unsigned numOverloadSets = 0;
1539-
// Let's count how many overload sets do we have.
1540-
while (!ApplyExprs.empty()) {
1541-
auto application = ApplyExprs.top();
1542-
auto applyExpr = application.first;
1543-
1544-
// Add overload sets tracked by current expression.
1545-
numOverloadSets += application.second;
1546-
ApplyExprs.pop();
1547-
1548-
// We've found the current expression, so record the number of
1549-
// overloads.
1550-
if (expr == applyExpr) {
1551-
ApplyExprs.push({ applyExpr, numOverloadSets });
1552-
break;
1553-
}
1554-
}
1555-
1556-
// If there are fewer than two overloads in the chain
1557-
// there is no point of solving this expression,
1558-
// because we won't be able to reduce it's domain.
1559-
if (numOverloadSets > 1)
1560-
SubExprs.push(Candidate(CS, expr));
1561-
1562-
return expr;
1563-
}
1564-
};
1565-
1566-
std::queue<Candidate> expressions;
1567-
ExprCollector collector(*this, expressions, domains);
1568-
1569-
// Collect all of the binary/unary and call sub-expressions
1570-
// so we can start solving them separately.
1571-
expr->walk(collector);
1572-
1573-
while (!expressions.empty()) {
1574-
auto &candidate = expressions.front();
1575-
1576-
// If there are no results, let's forget everything we know about the
1577-
// system so far. This actually is ok, because some of the expressions
1578-
// might require manual salvaging.
1579-
if (candidate.solve()) {
1580-
// Let's restore all of the original OSR domains.
1581-
for (auto &domain : domains) {
1582-
if (auto OSR = dyn_cast<OverloadSetRefExpr>(domain.getFirst())) {
1583-
OSR->setDecls(domain.getSecond());
1584-
}
1585-
}
1586-
break;
1587-
}
1588-
1589-
expressions.pop();
1590-
}
1591-
}
1592-
1593-
ConstraintSystem::SolutionKind
1594-
ConstraintSystem::solve(Expr *&expr,
1595-
Type convertType,
1596-
ExprTypeCheckListener *listener,
1597-
SmallVectorImpl<Solution> &solutions,
1598-
FreeTypeVariableBinding allowFreeTypeVariables) {
1599-
assert(!solverState && "use solveRec for recursive calls");
1600-
1601-
// Try to shrink the system by reducing disjunction domains. This
1602-
// goes through every sub-expression and generate it's own sub-system, to
1603-
// try to reduce the domains of those subexpressions.
1604-
shrink(expr);
1605-
1606-
// Generate constraints for the main system.
1607-
if (auto generatedExpr = generateConstraints(expr))
1608-
expr = generatedExpr;
1609-
else {
1610-
return SolutionKind::Error;
1611-
}
1612-
1613-
// If there is a type that we're expected to convert to, add the conversion
1614-
// constraint.
1615-
if (convertType) {
1616-
auto constraintKind = ConstraintKind::Conversion;
1617-
if (getContextualTypePurpose() == CTP_CallArgument)
1618-
constraintKind = ConstraintKind::ArgumentConversion;
1619-
1620-
if (allowFreeTypeVariables == FreeTypeVariableBinding::UnresolvedType) {
1621-
convertType = convertType.transform([&](Type type) -> Type {
1622-
if (type->is<UnresolvedType>())
1623-
return createTypeVariable(getConstraintLocator(expr), 0);
1624-
return type;
1625-
});
1626-
}
1627-
1628-
addConstraint(constraintKind, expr->getType(), convertType,
1629-
getConstraintLocator(expr), /*isFavored*/ true);
1630-
}
1631-
1632-
// Notify the listener that we've built the constraint system.
1633-
if (listener && listener->builtConstraints(*this, expr)) {
1634-
return SolutionKind::Error;
1635-
}
1636-
1637-
if (TC.getLangOpts().DebugConstraintSolver) {
1638-
auto &log = getASTContext().TypeCheckerDebug->getStream();
1639-
log << "---Initial constraints for the given expression---\n";
1640-
expr->print(log);
1641-
log << "\n";
1642-
print(log);
1643-
}
1644-
1645-
// Try to solve the constraint system using computed suggestions.
1646-
solve(solutions, allowFreeTypeVariables);
1647-
1648-
// If there are no solutions let's mark system as unsolved,
1649-
// and solved otherwise even if there are multiple solutions still present.
1650-
return solutions.empty() ? SolutionKind::Unsolved : SolutionKind::Solved;
1651-
}
1652-
16531336
bool ConstraintSystem::solve(SmallVectorImpl<Solution> &solutions,
16541337
FreeTypeVariableBinding allowFreeTypeVariables) {
16551338
assert(!solverState && "use solveRec for recursive calls");
@@ -1673,7 +1356,7 @@ bool ConstraintSystem::solve(SmallVectorImpl<Solution> &solutions,
16731356

16741357
// Remove the solver state.
16751358
this->solverState = nullptr;
1676-
1359+
16771360
// We fail if there is no solution.
16781361
return solutions.empty();
16791362
}

0 commit comments

Comments
 (0)