Skip to content

Commit c1ec0ca

Browse files
authored
Merge pull request #4766 from eeckstein/revert-tc
2 parents c1aee8a + 38cb48b commit c1ec0ca

File tree

3 files changed

+56
-188
lines changed

3 files changed

+56
-188
lines changed

lib/Sema/CSSolver.cpp

Lines changed: 51 additions & 172 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,6 +1342,13 @@ bool ConstraintSystem::Candidate::solve() {
13421342
// Allocate new constraint system for sub-expression.
13431343
ConstraintSystem cs(TC, DC, None);
13441344

1345+
// Set contextual type if present. This is done before constraint generation
1346+
// to give a "hint" to that operation about possible optimizations.
1347+
auto CT = IsPrimary ? CS.getContextualType() : CS.getContextualType(E);
1348+
if (!CT.isNull())
1349+
cs.setContextualType(E, CS.getContextualTypeLoc(),
1350+
CS.getContextualTypePurpose());
1351+
13451352
// Generate constraints for the new system.
13461353
if (auto generatedExpr = cs.generateConstraints(E)) {
13471354
E = generatedExpr;
@@ -1355,7 +1362,7 @@ bool ConstraintSystem::Candidate::solve() {
13551362
// constraint to the system.
13561363
if (!CT.isNull()) {
13571364
auto constraintKind = ConstraintKind::Conversion;
1358-
if (CTP == CTP_CallArgument)
1365+
if (CS.getContextualTypePurpose() == CTP_CallArgument)
13591366
constraintKind = ConstraintKind::ArgumentConversion;
13601367

13611368
cs.addConstraint(constraintKind, E->getType(), CT,
@@ -1469,21 +1476,52 @@ void ConstraintSystem::shrink(Expr *expr) {
14691476
std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
14701477
// A dictionary expression is just a set of tuples; try to solve ones
14711478
// that have overload sets.
1472-
if (auto collectionExpr = dyn_cast<CollectionExpr>(expr)) {
1473-
visitCollectionExpr(collectionExpr);
1479+
if (auto dictionaryExpr = dyn_cast<DictionaryExpr>(expr)) {
1480+
bool isPrimaryExpr = expr == PrimaryExpr;
1481+
for (auto element : dictionaryExpr->getElements()) {
1482+
unsigned numOverloads = 0;
1483+
element->walk(OverloadSetCounter(numOverloads));
1484+
1485+
// There are no overload sets in the element; skip it.
1486+
if (numOverloads == 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+
Candidates.push_back(Candidate(CS, dict, isPrimaryExpr));
1500+
}
1501+
14741502
// Don't try to walk into the dictionary.
1503+
return { false, expr };
1504+
}
1505+
1506+
// Consider all of the collections to be candidates,
1507+
// FIXME: try to split collections into parts for simplified solving.
1508+
if (isa<CollectionExpr>(expr)) {
1509+
Candidates.push_back(Candidate(CS, expr, false));
14751510
return {false, expr};
14761511
}
14771512

14781513
// Let's not attempt to type-check closures, which has already been
14791514
// type checked anyway.
14801515
if (isa<ClosureExpr>(expr)) {
1481-
return {false, expr};
1516+
return { false, expr };
14821517
}
14831518

1519+
// Coerce to type expressions are only viable if they have
1520+
// a single child expression.
14841521
if (auto coerceExpr = dyn_cast<CoerceExpr>(expr)) {
1485-
visitCoerceExpr(coerceExpr);
1486-
return {false, expr};
1522+
if (!coerceExpr->getSubExpr()) {
1523+
return { false, expr };
1524+
}
14871525
}
14881526

14891527
if (auto OSR = dyn_cast<OverloadSetRefExpr>(expr)) {
@@ -1501,24 +1539,12 @@ void ConstraintSystem::shrink(Expr *expr) {
15011539
}
15021540

15031541
Expr *walkToExprPost(Expr *expr) override {
1504-
if (expr == PrimaryExpr) {
1505-
// If this is primary expression and there are no candidates
1506-
// to be solved, let's not record it, because it's going to be
1507-
// solved irregardless.
1508-
if (Candidates.empty())
1509-
return expr;
1510-
1511-
auto contextualType = CS.getContextualType();
1512-
// If there is a contextual type set for this expression.
1513-
if (!contextualType.isNull()) {
1514-
Candidates.push_back(Candidate(CS, expr, contextualType,
1515-
CS.getContextualTypePurpose()));
1516-
return expr;
1517-
}
1518-
1519-
// Or it's a function application with other candidates present.
1520-
if (isa<ApplyExpr>(expr)) {
1521-
Candidates.push_back(Candidate(CS, expr));
1542+
// If there are sub-expressions to consider and
1543+
// contextual type is involved, let's add top-most expression
1544+
// to the queue just to make sure that we didn't miss any solutions.
1545+
if (expr == PrimaryExpr && !Candidates.empty()) {
1546+
if (!CS.getContextualType().isNull()) {
1547+
Candidates.push_back(Candidate(CS, expr, true));
15221548
return expr;
15231549
}
15241550
}
@@ -1548,157 +1574,10 @@ void ConstraintSystem::shrink(Expr *expr) {
15481574
// there is no point of solving this expression,
15491575
// because we won't be able to reduce its domain.
15501576
if (numOverloadSets > 1)
1551-
Candidates.push_back(Candidate(CS, expr));
1577+
Candidates.push_back(Candidate(CS, expr, expr == PrimaryExpr));
15521578

15531579
return expr;
15541580
}
1555-
1556-
private:
1557-
/// \brief Extract type of the element from given collection type.
1558-
///
1559-
/// \param collection The type of the collection container.
1560-
///
1561-
/// \returns ErrorType on failure, properly constructed type otherwise.
1562-
Type extractElementType(Type collection) {
1563-
auto &ctx = CS.getASTContext();
1564-
if (collection.isNull() || collection->is<ErrorType>())
1565-
return ErrorType::get(ctx);
1566-
1567-
auto base = collection.getPointer();
1568-
auto isInvalidType = [](Type type) -> bool {
1569-
return type.isNull() || type->hasUnresolvedType() ||
1570-
type->is<ErrorType>();
1571-
};
1572-
1573-
// Array type.
1574-
if (auto array = dyn_cast<ArraySliceType>(base)) {
1575-
auto elementType = array->getBaseType();
1576-
// If base type is invalid let's return error type.
1577-
return isInvalidType(elementType) ? ErrorType::get(ctx) : elementType;
1578-
}
1579-
1580-
// Map or Set or any other associated collection type.
1581-
if (auto boundGeneric = dyn_cast<BoundGenericType>(base)) {
1582-
if (boundGeneric->hasUnresolvedType())
1583-
return ErrorType::get(ctx);
1584-
1585-
llvm::SmallVector<TupleTypeElt, 2> params;
1586-
for (auto &type : boundGeneric->getGenericArgs()) {
1587-
// One of the generic arguments in invalid or unresolved.
1588-
if (isInvalidType(type))
1589-
return ErrorType::get(ctx);
1590-
1591-
params.push_back(type);
1592-
}
1593-
1594-
// If there is just one parameter, let's return it directly.
1595-
if (params.size() == 1)
1596-
return params[0].getType();
1597-
1598-
return TupleType::get(params, ctx);
1599-
}
1600-
1601-
return ErrorType::get(ctx);
1602-
}
1603-
1604-
bool isSuitableCollection(TypeRepr *collectionTypeRepr) {
1605-
// Only generic identifier, array or dictionary.
1606-
switch (collectionTypeRepr->getKind()) {
1607-
case TypeReprKind::GenericIdent:
1608-
case TypeReprKind::Array:
1609-
case TypeReprKind::Dictionary:
1610-
return true;
1611-
1612-
default:
1613-
return false;
1614-
}
1615-
}
1616-
1617-
void visitCoerceExpr(CoerceExpr *coerceExpr) {
1618-
auto subExpr = coerceExpr->getSubExpr();
1619-
// Coerce expression is valid only if it has sub-expression.
1620-
if (!subExpr) return;
1621-
1622-
unsigned numOverloadSets = 0;
1623-
subExpr->forEachChildExpr([&](Expr *childExpr) -> Expr * {
1624-
if (isa<OverloadSetRefExpr>(childExpr)) {
1625-
++numOverloadSets;
1626-
return childExpr;
1627-
}
1628-
1629-
if (auto nestedCoerceExpr = dyn_cast<CoerceExpr>(childExpr)) {
1630-
visitCoerceExpr(nestedCoerceExpr);
1631-
// Don't walk inside of nested coercion expression directly,
1632-
// that is be done by recursive call to visitCoerceExpr.
1633-
return nullptr;
1634-
}
1635-
1636-
// If sub-expression we are trying to coerce to type is a collection,
1637-
// let's allow collector discover it with assigned contextual type
1638-
// of coercion, which allows collections to be solved in parts.
1639-
if (auto collectionExpr = dyn_cast<CollectionExpr>(childExpr)) {
1640-
auto castTypeLoc = coerceExpr->getCastTypeLoc();
1641-
auto typeRepr = castTypeLoc.getTypeRepr();
1642-
1643-
if (typeRepr && isSuitableCollection(typeRepr)) {
1644-
// Clone representative to avoid modifying in-place,
1645-
// FIXME: We should try and silently resolve the type here,
1646-
// instead of cloning representative.
1647-
auto coercionRepr = typeRepr->clone(CS.getASTContext());
1648-
// Let's try to resolve coercion type from cloned representative.
1649-
auto coercionType = CS.TC.resolveType(coercionRepr, CS.DC,
1650-
TypeResolutionOptions());
1651-
1652-
// Looks like coercion type is invalid, let's skip this sub-tree.
1653-
if (coercionType->is<ErrorType>())
1654-
return nullptr;
1655-
1656-
// Visit collection expression inline.
1657-
visitCollectionExpr(collectionExpr, coercionType,
1658-
CTP_CoerceOperand);
1659-
}
1660-
}
1661-
1662-
return childExpr;
1663-
});
1664-
1665-
// It's going to be inefficient to try and solve
1666-
// coercion in parts, so let's just make it a candidate directly,
1667-
// if it contains at least a single overload set.
1668-
1669-
if (numOverloadSets > 0)
1670-
Candidates.push_back(Candidate(CS, coerceExpr));
1671-
}
1672-
1673-
void visitCollectionExpr(CollectionExpr *collectionExpr,
1674-
Type contextualType = Type(),
1675-
ContextualTypePurpose CTP = CTP_Unused) {
1676-
// If there is a contextual type set for this collection,
1677-
// let's propagate it to the candidate.
1678-
if (!contextualType.isNull()) {
1679-
auto elementType = extractElementType(contextualType);
1680-
// If we couldn't deduce element type for the collection, let's
1681-
// not attempt to solve it.
1682-
if (elementType->is<ErrorType>())
1683-
return;
1684-
1685-
contextualType = elementType;
1686-
}
1687-
1688-
for (auto element : collectionExpr->getElements()) {
1689-
unsigned numOverloads = 0;
1690-
element->walk(OverloadSetCounter(numOverloads));
1691-
1692-
// There are no overload sets in the element; skip it.
1693-
if (numOverloads == 0)
1694-
continue;
1695-
1696-
// Record each of the collection elements, which passed
1697-
// number of overload sets rule, as a candidate for solving
1698-
// with contextual type of the collection.
1699-
Candidates.push_back(Candidate(CS, element, contextualType, CTP));
1700-
}
1701-
}
17021581
};
17031582

17041583
ExprCollector collector(expr, *this, domains);

lib/Sema/ConstraintSystem.h

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,17 +1022,15 @@ class ConstraintSystem {
10221022
/// to reduce scopes of the overload sets (disjunctions) in the system.
10231023
class Candidate {
10241024
Expr *E;
1025+
bool IsPrimary;
1026+
1027+
ConstraintSystem &CS;
10251028
TypeChecker &TC;
10261029
DeclContext *DC;
10271030

1028-
// Contextual Information.
1029-
Type CT;
1030-
ContextualTypePurpose CTP;
1031-
10321031
public:
1033-
Candidate(ConstraintSystem &cs, Expr *expr, Type ct = Type(),
1034-
ContextualTypePurpose ctp = ContextualTypePurpose::CTP_Unused)
1035-
: E(expr), TC(cs.TC), DC(cs.DC), CT(ct), CTP(ctp) {}
1032+
Candidate(ConstraintSystem &cs, Expr *expr, bool primaryExpr)
1033+
: E(expr), IsPrimary(primaryExpr), CS(cs), TC(cs.TC), DC(cs.DC) {}
10361034

10371035
/// \brief Return underlaying expression.
10381036
Expr *getExpr() const { return E; }

test/Sema/complex_expressions.swift

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,3 @@ struct P {
8787
func sr1794(pt: P, p0: P, p1: P) -> Bool {
8888
return (pt.x - p0.x) * (p1.y - p0.y) - (pt.y - p0.y) * (p1.x - p0.x) < 0.0
8989
}
90-
91-
// Tests for partial contextual type application in sub-expressions
92-
93-
let v1 = (1 - 2 / 3 * 6) as UInt
94-
let v2 = (([1 + 2 * 3, 4, 5])) as [UInt]
95-
let v3 = ["hello": 1 + 2, "world": 3 + 4 + 5 * 3] as Dictionary<String, UInt>
96-
let v4 = [1 + 2 + 3, 4] as [UInt32] + [2 * 3] as [UInt32]
97-
let v5 = ([1 + 2 + 3, 4] as [UInt32]) + ([2 * 3] as [UInt32])
98-
let v6 = [1 + 2 + 3, 4] as Set<UInt32>

0 commit comments

Comments
 (0)