Skip to content

Commit 5d0d8d9

Browse files
DougGregorrjmccall
authored andcommitted
[Constraint solver] Capture/roll back type mappings generated while solving.
When we perform constraint generation while solving, capture the type mappings we generate as part of the solver scope and solutions, rolling them back and replaying them as necessary. Otherwise, we’ll end up with uses of stale type variables, expression/parameter/type-loc types set twice, etc. Fixes rdar://problem/50390449 and rdar://problem/50150314.
1 parent 83b5b2f commit 5d0d8d9

File tree

5 files changed

+83
-22
lines changed

5 files changed

+83
-22
lines changed

lib/Sema/CSApply.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7487,6 +7487,11 @@ Expr *ConstraintSystem::applySolution(Solution &solution, Expr *expr,
74877487
Type convertType,
74887488
bool discardedExpr,
74897489
bool skipClosures) {
7490+
// Add the node types back.
7491+
for (auto &nodeType : solution.addedNodeTypes) {
7492+
setType(nodeType.first, nodeType.second);
7493+
}
7494+
74907495
// If any fixes needed to be applied to arrive at this solution, resolve
74917496
// them to specific expressions.
74927497
if (!solution.Fixes.empty()) {

lib/Sema/CSSolver.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,10 +169,19 @@ Solution ConstraintSystem::finalize() {
169169
solution.DefaultedConstraints.insert(DefaultedConstraints.begin(),
170170
DefaultedConstraints.end());
171171

172+
for (auto &nodeType : addedNodeTypes) {
173+
solution.addedNodeTypes.push_back(nodeType);
174+
}
175+
172176
for (auto &e : CheckedConformances)
173177
solution.Conformances.push_back({e.first, e.second});
174178

175179
for (const auto &transformed : builderTransformedClosures) {
180+
auto known =
181+
solution.builderTransformedClosures.find(std::get<0>(transformed));
182+
if (known != solution.builderTransformedClosures.end()) {
183+
assert(known->second.second == std::get<2>(transformed));
184+
}
176185
solution.builderTransformedClosures.insert(
177186
std::make_pair(std::get<0>(transformed),
178187
std::make_pair(std::get<1>(transformed),
@@ -240,6 +249,11 @@ void ConstraintSystem::applySolution(const Solution &solution) {
240249
solution.DefaultedConstraints.begin(),
241250
solution.DefaultedConstraints.end());
242251

252+
// Add the node types back.
253+
for (auto &nodeType : solution.addedNodeTypes) {
254+
setType(nodeType.first, nodeType.second);
255+
}
256+
243257
// Register the conformances checked along the way to arrive to solution.
244258
for (auto &conformance : solution.Conformances)
245259
CheckedConformances.push_back(conformance);
@@ -442,6 +456,7 @@ ConstraintSystem::SolverScope::SolverScope(ConstraintSystem &cs)
442456
numOpenedTypes = cs.OpenedTypes.size();
443457
numOpenedExistentialTypes = cs.OpenedExistentialTypes.size();
444458
numDefaultedConstraints = cs.DefaultedConstraints.size();
459+
numAddedNodeTypes = cs.addedNodeTypes.size();
445460
numCheckedConformances = cs.CheckedConformances.size();
446461
numMissingMembers = cs.MissingMembers.size();
447462
numDisabledConstraints = cs.solverState->getNumDisabledConstraints();
@@ -495,6 +510,12 @@ ConstraintSystem::SolverScope::~SolverScope() {
495510
// Remove any defaulted type variables.
496511
truncate(cs.DefaultedConstraints, numDefaultedConstraints);
497512

513+
// Remove any node types we registered.
514+
for (unsigned i : range(numAddedNodeTypes, cs.addedNodeTypes.size())) {
515+
cs.eraseType(cs.addedNodeTypes[i].first);
516+
}
517+
truncate(cs.addedNodeTypes, numAddedNodeTypes);
518+
498519
// Remove any conformances checked along the current path.
499520
truncate(cs.CheckedConformances, numCheckedConformances);
500521

lib/Sema/ConstraintSystem.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3261,6 +3261,12 @@ ConstraintSystem::TypeMatchResult ConstraintSystem::applyFunctionBuilder(
32613261
assert(transformedType && "Missing type");
32623262

32633263
// Record the transformation.
3264+
assert(std::find_if(builderTransformedClosures.begin(),
3265+
builderTransformedClosures.end(),
3266+
[&](const std::tuple<ClosureExpr *, Type, Expr *> &elt) {
3267+
return std::get<0>(elt) == closure;
3268+
}) == builderTransformedClosures.end() &&
3269+
"already transformed this closure along this path!?!");
32643270
builderTransformedClosures.push_back(
32653271
std::make_tuple(closure, builderType, singleExpr));
32663272

lib/Sema/ConstraintSystem.h

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,9 @@ struct Score {
570570

571571
};
572572

573+
/// An AST node that can gain type information while solving.
574+
using TypedNode = llvm::PointerUnion3<Expr *, TypeLoc *, ParamDecl *>;
575+
573576
/// Display a score.
574577
llvm::raw_ostream &operator<<(llvm::raw_ostream &out, const Score &score);
575578

@@ -642,6 +645,9 @@ class Solution {
642645
/// The locators of \c Defaultable constraints whose defaults were used.
643646
llvm::SmallPtrSet<ConstraintLocator *, 2> DefaultedConstraints;
644647

648+
/// The node -> type mappings introduced by this solution.
649+
llvm::SmallVector<std::pair<TypedNode, Type>, 8> addedNodeTypes;
650+
645651
std::vector<std::pair<ConstraintLocator *, ProtocolConformanceRef>>
646652
Conformances;
647653

@@ -1106,6 +1112,9 @@ class ConstraintSystem {
11061112
SmallVector<std::pair<ConstraintLocator *, OpenedArchetypeType *>, 4>
11071113
OpenedExistentialTypes;
11081114

1115+
/// The node -> type mappings introduced by generating constraints.
1116+
llvm::SmallVector<std::pair<TypedNode, Type>, 8> addedNodeTypes;
1117+
11091118
std::vector<std::pair<ConstraintLocator *, ProtocolConformanceRef>>
11101119
CheckedConformances;
11111120

@@ -1586,6 +1595,8 @@ class ConstraintSystem {
15861595
/// The length of \c DefaultedConstraints.
15871596
unsigned numDefaultedConstraints;
15881597

1598+
unsigned numAddedNodeTypes;
1599+
15891600
unsigned numCheckedConformances;
15901601

15911602
unsigned numMissingMembers;
@@ -1736,33 +1747,56 @@ class ConstraintSystem {
17361747
this->FavoredTypes[E] = T;
17371748
}
17381749

1750+
/// Set the type in our type map for the given node.
1751+
///
1752+
/// The side tables are used through the expression type checker to avoid mutating nodes until
1753+
/// we know we have successfully type-checked them.
1754+
void setType(TypedNode node, Type type) {
1755+
assert(!node.isNull() && "Cannot set type information on null node");
1756+
assert(type && "Expected non-null type");
1757+
1758+
// Record the type.
1759+
if (auto expr = node.dyn_cast<Expr *>()) {
1760+
ExprTypes[expr] = type.getPointer();
1761+
} else if (auto typeLoc = node.dyn_cast<TypeLoc *>()) {
1762+
TypeLocTypes[typeLoc] = type.getPointer();
1763+
} else {
1764+
auto param = node.get<ParamDecl *>();
1765+
ParamTypes[param] = type.getPointer();
1766+
}
1767+
1768+
// Record the fact that we ascribed a type to this node.
1769+
if (solverState && solverState->depth > 0) {
1770+
addedNodeTypes.push_back({node, type});
1771+
}
1772+
}
1773+
17391774
/// Set the type in our type map for a given expression. The side
17401775
/// map is used throughout the expression type checker in order to
17411776
/// avoid mutating expressions until we know we have successfully
17421777
/// type-checked them.
17431778
void setType(Expr *E, Type T) {
1744-
assert(E != nullptr && "Expected non-null expression!");
1745-
assert(T && "Expected non-null type!");
1746-
1747-
// FIXME: We sometimes set the type and then later set it to a
1748-
// value that is slightly different, e.g. not an lvalue.
1749-
// assert((ExprTypes.find(E) == ExprTypes.end() ||
1750-
// ExprTypes.find(E)->second->isEqual(T) ||
1751-
// ExprTypes.find(E)->second->hasTypeVariable()) &&
1752-
// "Expected type to be invariant!");
1753-
1754-
ExprTypes[E] = T.getPointer();
1779+
setType(TypedNode(E), T);
17551780
}
17561781

17571782
void setType(TypeLoc &L, Type T) {
1758-
assert(T && "Expected non-null type!");
1759-
TypeLocTypes[&L] = T.getPointer();
1783+
setType(TypedNode(&L), T);
17601784
}
17611785

17621786
void setType(ParamDecl *P, Type T) {
1763-
assert(P && "Expected non-null parameter!");
1764-
assert(T && "Expected non-null type!");
1765-
ParamTypes[P] = T.getPointer();
1787+
setType(TypedNode(P), T);
1788+
}
1789+
1790+
/// Erase the type for the given node.
1791+
void eraseType(TypedNode node) {
1792+
if (auto expr = node.dyn_cast<Expr *>()) {
1793+
ExprTypes.erase(expr);
1794+
} else if (auto typeLoc = node.dyn_cast<TypeLoc *>()) {
1795+
TypeLocTypes.erase(typeLoc);
1796+
} else {
1797+
auto param = node.get<ParamDecl *>();
1798+
ParamTypes.erase(param);
1799+
}
17661800
}
17671801

17681802
void setType(KeyPathExpr *KP, unsigned I, Type T) {

test/Constraints/function_builder_diags.swift

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,8 @@ func testOverloading(name: String) {
114114

115115
let _: A = a1
116116

117-
#if false
118-
// FIXME: Using the overloads causes a crash, which is likely related
119-
// to us generating the constraints from the child expressions multiple
120-
// times.
121-
let b1 = overloadedTuplify(true) { b in
117+
_ = overloadedTuplify(true) { b in
122118
b ? "Hello, \(name)" : "Goodbye"
123119
42
124120
}
125-
#endif
126121
}

0 commit comments

Comments
 (0)