Prevent infinite loops when checking something like "foo".0.1.2
This commit is contained in:
parent
f2550e9430
commit
a2701257dd
2 changed files with 26 additions and 6 deletions
|
@ -265,7 +265,12 @@ namespace bolt {
|
|||
*/
|
||||
std::deque<class Constraint*> Queue;
|
||||
|
||||
void unify(Type* Left, Type* Right, Node* Source);
|
||||
/**
|
||||
* Unify two types, using `Source` as source location.
|
||||
*
|
||||
* \returns Whether a type variable was assigned a type or not.
|
||||
*/
|
||||
bool unify(Type* Left, Type* Right, Node* Source);
|
||||
|
||||
void solve(Constraint* Constraint);
|
||||
|
||||
|
|
|
@ -1294,8 +1294,18 @@ namespace bolt {
|
|||
void Checker::solve(Constraint* Constraint) {
|
||||
|
||||
Queue.push_back(Constraint);
|
||||
bool DidJoin = false;
|
||||
std::deque<class Constraint*> NextQueue;
|
||||
|
||||
while (!Queue.empty()) {
|
||||
while (true) {
|
||||
|
||||
if (Queue.empty()) {
|
||||
if (NextQueue.empty() || !DidJoin) {
|
||||
break;
|
||||
}
|
||||
DidJoin = false;
|
||||
std::swap(Queue, NextQueue);
|
||||
}
|
||||
|
||||
auto Constraint = Queue.front();
|
||||
Queue.pop_front();
|
||||
|
@ -1318,7 +1328,7 @@ namespace bolt {
|
|||
unify(ElementTy, Field->FieldTy, Field->Source);
|
||||
}
|
||||
} else if (MaybeTuple->isVar()) {
|
||||
// TODO Add logic for when tuple is a var
|
||||
NextQueue.push_back(Constraint);
|
||||
} else {
|
||||
DE.add<NotATupleDiagnostic>(MaybeTuple, Field->Source);
|
||||
}
|
||||
|
@ -1337,7 +1347,9 @@ namespace bolt {
|
|||
case ConstraintKind::Equal:
|
||||
{
|
||||
auto Equal = static_cast<CEqual*>(Constraint);
|
||||
unify(Equal->Left, Equal->Right, Equal->Source);
|
||||
if (unify(Equal->Left, Equal->Right, Equal->Source)) {
|
||||
DidJoin = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1413,11 +1425,11 @@ namespace bolt {
|
|||
Type* Right;
|
||||
Node* Source;
|
||||
|
||||
|
||||
// Internal state used by the unifier
|
||||
ByteString CurrentFieldName;
|
||||
TypePath LeftPath;
|
||||
TypePath RightPath;
|
||||
bool DidJoin = false;
|
||||
|
||||
Type* getLeft() const {
|
||||
return Left;
|
||||
|
@ -1525,6 +1537,8 @@ namespace bolt {
|
|||
|
||||
TV->set(Ty);
|
||||
|
||||
DidJoin = true;
|
||||
|
||||
propagateClasses(TV->asVar().Context, Ty);
|
||||
|
||||
// This is a very specific adjustment that is critical to the
|
||||
|
@ -1826,10 +1840,11 @@ namespace bolt {
|
|||
return false;
|
||||
}
|
||||
|
||||
void Checker::unify(Type* Left, Type* Right, Node* Source) {
|
||||
bool Checker::unify(Type* Left, Type* Right, Node* Source) {
|
||||
// std::cerr << describe(C->Left) << " ~ " << describe(C->Right) << std::endl;
|
||||
Unifier A { *this, Left, Right, Source };
|
||||
A.unify();
|
||||
return A.DidJoin;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue