Skip to content

Commit ddf31e6

Browse files
authored
Merge pull request swiftlang#4530 from xedin/DSP-1794
2 parents d5b7123 + 2011e50 commit ddf31e6

File tree

3 files changed

+62
-25
lines changed

3 files changed

+62
-25
lines changed

lib/Sema/CSSolver.cpp

+44-16
Original file line numberDiff line numberDiff line change
@@ -1346,8 +1346,10 @@ bool ConstraintSystem::Candidate::solve() {
13461346

13471347
// Set contextual type if present. This is done before constraint generation
13481348
// to give a "hint" to that operation about possible optimizations.
1349+
auto CT = IsPrimary ? CS.getContextualType() : CS.getContextualType(E);
13491350
if (!CT.isNull())
1350-
cs.setContextualType(E, CT, CTP);
1351+
cs.setContextualType(E, CS.getContextualTypeLoc(),
1352+
CS.getContextualTypePurpose());
13511353

13521354
// Generate constraints for the new system.
13531355
if (auto generatedExpr = cs.generateConstraints(E)) {
@@ -1362,10 +1364,10 @@ bool ConstraintSystem::Candidate::solve() {
13621364
// constraint to the system.
13631365
if (!CT.isNull()) {
13641366
auto constraintKind = ConstraintKind::Conversion;
1365-
if (CTP == CTP_CallArgument)
1367+
if (CS.getContextualTypePurpose() == CTP_CallArgument)
13661368
constraintKind = ConstraintKind::ArgumentConversion;
13671369

1368-
cs.addConstraint(constraintKind, E->getType(), CT.getType(),
1370+
cs.addConstraint(constraintKind, E->getType(), CT,
13691371
cs.getConstraintLocator(E), /*isFavored=*/true);
13701372
}
13711373

@@ -1452,6 +1454,8 @@ void ConstraintSystem::shrink(Expr *expr) {
14521454
DomainMap domains;
14531455

14541456
struct ExprCollector : public ASTWalker {
1457+
Expr *PrimaryExpr;
1458+
14551459
// The primary constraint system.
14561460
ConstraintSystem &CS;
14571461

@@ -1469,15 +1473,15 @@ void ConstraintSystem::shrink(Expr *expr) {
14691473
// so they can be restored in case of failure.
14701474
DomainMap &Domains;
14711475

1472-
ExprCollector(ConstraintSystem &cs,
1473-
std::queue<Candidate> &container,
1474-
DomainMap &domains)
1475-
: CS(cs), SubExprs(container), Domains(domains) { }
1476+
ExprCollector(Expr *expr, ConstraintSystem &cs,
1477+
std::queue<Candidate> &container, DomainMap &domains)
1478+
: PrimaryExpr(expr), CS(cs), SubExprs(container), Domains(domains) {}
14761479

14771480
std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
14781481
// A dictionary expression is just a set of tuples; try to solve ones
14791482
// that have overload sets.
14801483
if (auto dictionaryExpr = dyn_cast<DictionaryExpr>(expr)) {
1484+
bool isPrimaryExpr = expr == PrimaryExpr;
14811485
for (auto element : dictionaryExpr->getElements()) {
14821486
unsigned numOverlaods = 0;
14831487
element->walk(OverloadSetCounter(numOverlaods));
@@ -1496,13 +1500,20 @@ void ConstraintSystem::shrink(Expr *expr) {
14961500

14971501
// Make each of the dictionary elements an independent dictionary,
14981502
// such makes it easy to type-check everything separately.
1499-
SubExprs.push(Candidate(CS, dict));
1503+
SubExprs.push(Candidate(CS, dict, isPrimaryExpr));
15001504
}
15011505

15021506
// Don't try to walk into the dictionary.
15031507
return { false, expr };
15041508
}
15051509

1510+
// Consider all of the collections to be candidates,
1511+
// FIXME: try to split collections into parts for simplified solving.
1512+
if (isa<CollectionExpr>(expr)) {
1513+
SubExprs.push(Candidate(CS, expr, false));
1514+
return {false, expr};
1515+
}
1516+
15061517
// Let's not attempt to type-check closures or default values,
15071518
// which has already been type checked anyway.
15081519
if (isa<ClosureExpr>(expr) || isa<DefaultValueExpr>(expr)) {
@@ -1532,6 +1543,16 @@ void ConstraintSystem::shrink(Expr *expr) {
15321543
}
15331544

15341545
Expr *walkToExprPost(Expr *expr) override {
1546+
// If there are sub-expressions to consider and
1547+
// contextual type is involved, let's add top-most expression
1548+
// to the queue just to make sure that we didn't miss any solutions.
1549+
if (expr == PrimaryExpr && !SubExprs.empty()) {
1550+
if (!CS.getContextualType().isNull()) {
1551+
SubExprs.push(Candidate(CS, expr, true));
1552+
return expr;
1553+
}
1554+
}
1555+
15351556
if (!isa<ApplyExpr>(expr))
15361557
return expr;
15371558

@@ -1557,14 +1578,14 @@ void ConstraintSystem::shrink(Expr *expr) {
15571578
// there is no point of solving this expression,
15581579
// because we won't be able to reduce it's domain.
15591580
if (numOverloadSets > 1)
1560-
SubExprs.push(Candidate(CS, expr));
1581+
SubExprs.push(Candidate(CS, expr, expr == PrimaryExpr));
15611582

15621583
return expr;
15631584
}
15641585
};
15651586

15661587
std::queue<Candidate> expressions;
1567-
ExprCollector collector(*this, expressions, domains);
1588+
ExprCollector collector(expr, *this, expressions, domains);
15681589

15691590
// Collect all of the binary/unary and call sub-expressions
15701591
// so we can start solving them separately.
@@ -1577,13 +1598,20 @@ void ConstraintSystem::shrink(Expr *expr) {
15771598
// system so far. This actually is ok, because some of the expressions
15781599
// might require manual salvaging.
15791600
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());
1601+
// Let's restore all of the original OSR domains for this sub-expression,
1602+
// this means that we can still make forward progress with solving of the
1603+
// top sub-expressions.
1604+
candidate.getExpr()->forEachChildExpr([&](Expr *childExpr) -> Expr * {
1605+
if (auto OSR = dyn_cast<OverloadSetRefExpr>(childExpr)) {
1606+
auto domain = domains.find(OSR);
1607+
if (domain == domains.end())
1608+
return childExpr;
1609+
1610+
OSR->setDecls(domain->getSecond());
15841611
}
1585-
}
1586-
break;
1612+
1613+
return childExpr;
1614+
});
15871615
}
15881616

15891617
expressions.pop();

lib/Sema/ConstraintSystem.h

+8-9
Original file line numberDiff line numberDiff line change
@@ -1022,19 +1022,18 @@ 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;
1027-
TypeLoc CT;
1028-
ContextualTypePurpose CTP;
10291030

10301031
public:
1031-
Candidate(ConstraintSystem &cs, Expr *expr)
1032-
: E(expr),
1033-
TC(cs.TC),
1034-
DC(cs.DC),
1035-
CT(cs.getContextualTypeLoc()),
1036-
CTP(cs.getContextualTypePurpose())
1037-
{}
1032+
Candidate(ConstraintSystem &cs, Expr *expr, bool primaryExpr)
1033+
: E(expr), IsPrimary(primaryExpr), CS(cs), TC(cs.TC), DC(cs.DC) {}
1034+
1035+
/// \brief Return underlaying expression.
1036+
Expr *getExpr() const { return E; }
10381037

10391038
/// \brief Try to solve this candidate sub-expression
10401039
/// and re-write it's OSR domains afterwards.

test/Sema/complex_expressions.swift

+10
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,13 @@ var operations: Dictionary<String, Operation> = [
7777
}),
7878
"=": .equals,
7979
]
80+
81+
// SR-1794
82+
struct P {
83+
let x: Float
84+
let y: Float
85+
}
86+
87+
func sr1794(pt: P, p0: P, p1: P) -> Bool {
88+
return (pt.x - p0.x) * (p1.y - p0.y) - (pt.y - p0.y) * (p1.x - p0.x) < 0.0
89+
}

0 commit comments

Comments
 (0)