mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Type checker] Don't re-insert node types when merging solutions.
Merging partial solutions can end up assigning the same type to a particular typed node (expression, parameter, etc.), which can lead to unbalanced set/clear when exploring the solution space (and later on, crashes). Don't re-insert such information. This is the same approach taken for type variable bindings, but it's all pretty unfortunate: partial solutions should only record information relative to their part of the constraint system, which would save time and memory during solving. Howver, that's too big a change for right now. Fixes rdar://problem/50853028.
This commit is contained in:
@@ -251,7 +251,8 @@ void ConstraintSystem::applySolution(const Solution &solution) {
|
|||||||
|
|
||||||
// Add the node types back.
|
// Add the node types back.
|
||||||
for (auto &nodeType : solution.addedNodeTypes) {
|
for (auto &nodeType : solution.addedNodeTypes) {
|
||||||
setType(nodeType.first, nodeType.second);
|
if (!hasType(nodeType.first))
|
||||||
|
setType(nodeType.first, nodeType.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the conformances checked along the way to arrive to solution.
|
// Register the conformances checked along the way to arrive to solution.
|
||||||
|
|||||||
@@ -571,7 +571,9 @@ struct Score {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// An AST node that can gain type information while solving.
|
/// An AST node that can gain type information while solving.
|
||||||
using TypedNode = llvm::PointerUnion3<Expr *, TypeLoc *, ParamDecl *>;
|
using TypedNode =
|
||||||
|
llvm::PointerUnion3<const Expr *, const TypeLoc *,
|
||||||
|
const ParamDecl *>;
|
||||||
|
|
||||||
/// Display a score.
|
/// Display a score.
|
||||||
llvm::raw_ostream &operator<<(llvm::raw_ostream &out, const Score &score);
|
llvm::raw_ostream &operator<<(llvm::raw_ostream &out, const Score &score);
|
||||||
@@ -1756,12 +1758,12 @@ public:
|
|||||||
assert(type && "Expected non-null type");
|
assert(type && "Expected non-null type");
|
||||||
|
|
||||||
// Record the type.
|
// Record the type.
|
||||||
if (auto expr = node.dyn_cast<Expr *>()) {
|
if (auto expr = node.dyn_cast<const Expr *>()) {
|
||||||
ExprTypes[expr] = type.getPointer();
|
ExprTypes[expr] = type.getPointer();
|
||||||
} else if (auto typeLoc = node.dyn_cast<TypeLoc *>()) {
|
} else if (auto typeLoc = node.dyn_cast<const TypeLoc *>()) {
|
||||||
TypeLocTypes[typeLoc] = type.getPointer();
|
TypeLocTypes[typeLoc] = type.getPointer();
|
||||||
} else {
|
} else {
|
||||||
auto param = node.get<ParamDecl *>();
|
auto param = node.get<const ParamDecl *>();
|
||||||
ParamTypes[param] = type.getPointer();
|
ParamTypes[param] = type.getPointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1775,26 +1777,18 @@ public:
|
|||||||
/// map is used throughout the expression type checker in order to
|
/// map is used throughout the expression type checker in order to
|
||||||
/// avoid mutating expressions until we know we have successfully
|
/// avoid mutating expressions until we know we have successfully
|
||||||
/// type-checked them.
|
/// type-checked them.
|
||||||
void setType(Expr *E, Type T) {
|
|
||||||
setType(TypedNode(E), T);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setType(TypeLoc &L, Type T) {
|
void setType(TypeLoc &L, Type T) {
|
||||||
setType(TypedNode(&L), T);
|
setType(TypedNode(&L), T);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setType(ParamDecl *P, Type T) {
|
|
||||||
setType(TypedNode(P), T);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Erase the type for the given node.
|
/// Erase the type for the given node.
|
||||||
void eraseType(TypedNode node) {
|
void eraseType(TypedNode node) {
|
||||||
if (auto expr = node.dyn_cast<Expr *>()) {
|
if (auto expr = node.dyn_cast<const Expr *>()) {
|
||||||
ExprTypes.erase(expr);
|
ExprTypes.erase(expr);
|
||||||
} else if (auto typeLoc = node.dyn_cast<TypeLoc *>()) {
|
} else if (auto typeLoc = node.dyn_cast<const TypeLoc *>()) {
|
||||||
TypeLocTypes.erase(typeLoc);
|
TypeLocTypes.erase(typeLoc);
|
||||||
} else {
|
} else {
|
||||||
auto param = node.get<ParamDecl *>();
|
auto param = node.get<const ParamDecl *>();
|
||||||
ParamTypes.erase(param);
|
ParamTypes.erase(param);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1812,12 +1806,20 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool hasType(const TypeLoc &L) const {
|
bool hasType(const TypeLoc &L) const {
|
||||||
return TypeLocTypes.find(&L) != TypeLocTypes.end();
|
return hasType(TypedNode(&L));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasType(const ParamDecl *P) const {
|
/// Check to see if we have a type for a node.
|
||||||
assert(P != nullptr && "Expected non-null parameter!");
|
bool hasType(TypedNode node) const {
|
||||||
return ParamTypes.find(P) != ParamTypes.end();
|
assert(!node.isNull() && "Expected non-null node");
|
||||||
|
if (auto expr = node.dyn_cast<const Expr *>()) {
|
||||||
|
return ExprTypes.find(expr) != ExprTypes.end();
|
||||||
|
} else if (auto typeLoc = node.dyn_cast<const TypeLoc *>()) {
|
||||||
|
return TypeLocTypes.find(typeLoc) != TypeLocTypes.end();
|
||||||
|
} else {
|
||||||
|
auto param = node.get<const ParamDecl *>();
|
||||||
|
return ParamTypes.find(param) != ParamTypes.end();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasType(const KeyPathExpr *KP, unsigned I) const {
|
bool hasType(const KeyPathExpr *KP, unsigned I) const {
|
||||||
|
|||||||
@@ -117,5 +117,12 @@ func testOverloading(name: String) {
|
|||||||
_ = overloadedTuplify(true) { b in
|
_ = overloadedTuplify(true) { b in
|
||||||
b ? "Hello, \(name)" : "Goodbye"
|
b ? "Hello, \(name)" : "Goodbye"
|
||||||
42
|
42
|
||||||
|
overloadedTuplify(false) {
|
||||||
|
$0 ? "Hello, \(name)" : "Goodbye"
|
||||||
|
42
|
||||||
|
if b {
|
||||||
|
"Hello, \(name)"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user