Switch to field constraints instead of TTupleIndex

This commit is contained in:
Sam Vervaeck 2024-01-21 01:04:13 +01:00
parent 4ab4094acc
commit 3942004f76
Signed by: samvv
SSH key fingerprint: SHA256:dIg0ywU1OP+ZYifrYxy8c5esO72cIKB+4/9wkZj1VaY
6 changed files with 103 additions and 193 deletions

View file

@ -1,8 +1,6 @@
#pragma once
#include "zen/config.hpp"
#include "bolt/ByteString.hpp"
#include "bolt/Common.hpp"
#include "bolt/CST.hpp"
@ -11,7 +9,6 @@
#include <cstdlib>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <deque>
@ -77,6 +74,7 @@ namespace bolt {
enum class ConstraintKind {
Equal,
Field,
Many,
Empty,
};
@ -112,6 +110,19 @@ namespace bolt {
};
class CField : public Constraint {
public:
Type* TupleTy;
size_t I;
Type* FieldTy;
Node* Source;
inline CField(Type* TupleTy, size_t I, Type* FieldTy, Node* Source = nullptr):
Constraint(ConstraintKind::Field), TupleTy(TupleTy), I(I), FieldTy(FieldTy), Source(Source) {}
};
class CMany : public Constraint {
public:
@ -254,7 +265,7 @@ namespace bolt {
*/
std::deque<class Constraint*> Queue;
void solveEqual(CEqual* C);
void unify(Type* Left, Type* Right, Node* Source);
void solve(Constraint* Constraint);
@ -276,11 +287,6 @@ namespace bolt {
Checker(const LanguageConfig& Config, DiagnosticEngine& DE);
/**
* \internal
*/
Type* simplifyType(Type* Ty);
/**
* \internal
*/

View file

@ -170,9 +170,14 @@ namespace bolt {
Type* Tuple;
std::size_t I;
Node* Source;
inline TupleIndexOutOfRangeDiagnostic(Type* Tuple, std::size_t I):
Diagnostic(DiagnosticKind::TupleIndexOutOfRange), Tuple(Tuple), I(I) {}
inline TupleIndexOutOfRangeDiagnostic(Type* Tuple, std::size_t I, Node* Source):
Diagnostic(DiagnosticKind::TupleIndexOutOfRange), Tuple(Tuple), I(I), Source(Source) {}
inline Node * getNode() const override {
return Source;
}
unsigned getCode() const noexcept override {
return 2015;
@ -221,9 +226,14 @@ namespace bolt {
public:
Type* Ty;
Node* Source;
inline NotATupleDiagnostic(Type* Ty):
Diagnostic(DiagnosticKind::NotATuple), Ty(Ty) {}
inline NotATupleDiagnostic(Type* Ty, Node* Source):
Diagnostic(DiagnosticKind::NotATuple), Ty(Ty), Source(Source) {}
inline Node * getNode() const override {
return Source;
}
unsigned getCode() const noexcept override {
return 2016;

View file

@ -9,7 +9,6 @@
#include <vector>
#include "zen/config.hpp"
#include "zen/range.hpp"
#include "bolt/CST.hpp"
#include "bolt/ByteString.hpp"
@ -48,7 +47,6 @@ namespace bolt {
TupleElement,
FieldType,
FieldRestType,
TupleIndexType,
PresentType,
End,
};
@ -105,10 +103,6 @@ namespace bolt {
return { TypeIndexKind::AppArgType };
}
static TypeIndex forTupleIndexType() {
return { TypeIndexKind::TupleIndexType };
}
static TypeIndex forPresentType() {
return { TypeIndexKind::PresentType };
}
@ -157,7 +151,6 @@ namespace bolt {
App,
Arrow,
Tuple,
TupleIndex,
Field,
Nil,
Absent,
@ -225,15 +218,6 @@ namespace bolt {
};
struct TTupleIndex {
Type* Ty;
std::size_t I;
bool operator==(const TTupleIndex& Other) const;
};
struct TNil {
bool operator==(const TNil& Other) const;
};
@ -266,7 +250,6 @@ namespace bolt {
TVar Var;
TArrow Arrow;
TTuple Tuple;
TTupleIndex TupleIndex;
TNil Nil;
TField Field;
TAbsent Absent;
@ -288,9 +271,6 @@ namespace bolt {
Type(TTuple&& Tuple):
Kind(TypeKind::Tuple), Tuple(std::move(Tuple)) {};
Type(TTupleIndex&& TupleIndex):
Kind(TypeKind::TupleIndex), TupleIndex(std::move(TupleIndex)) {};
Type(TNil&& Nil):
Kind(TypeKind::Nil), Nil(std::move(Nil)) {};
@ -303,46 +283,6 @@ namespace bolt {
Type(TPresent&& Present):
Kind(TypeKind::Present), Present(std::move(Present)) {};
// Type(TCon Con): Kind(TypeKind::Con) {
// new (&Con)TCon(Con);
// }
// Type(TApp App): Kind(TypeKind::App) {
// new (&App)TApp(App);
// }
// Type(TVar Var): Kind(TypeKind::Var) {
// new (&Var)TVar(Var);
// }
// Type(TArrow Arrow): Kind(TypeKind::Arrow) {
// new (&Arrow)TArrow(Arrow);
// }
// Type(TTuple Tuple): Kind(TypeKind::Tuple) {
// new (&Tuple)TTuple(Tuple);
// }
// Type(TTupleIndex TupleIndex): Kind(TypeKind::TupleIndex) {
// new (&TupleIndex)TTupleIndex(TupleIndex);
// }
// Type(TNil Nil): Kind(TypeKind::Nil) {
// new (&Nil)TNil(Nil);
// }
// Type(TField Field): Kind(TypeKind::Field) {
// new (&Field)TField(Field);
// }
// Type(TAbsent Absent): Kind(TypeKind::Absent) {
// new (&Absent)TAbsent(Absent);
// }
// Type(TPresent Present): Kind(TypeKind::Present) {
// new (&Present)TPresent(Present);
// }
Type(const Type& Other): Kind(Other.Kind) {
switch (Kind) {
case TypeKind::Con:
@ -360,9 +300,6 @@ namespace bolt {
case TypeKind::Tuple:
new (&Tuple)TTuple(Other.Tuple);
break;
case TypeKind::TupleIndex:
new (&TupleIndex)TTupleIndex(Other.TupleIndex);
break;
case TypeKind::Nil:
new (&Nil)TNil(Other.Nil);
break;
@ -395,9 +332,6 @@ namespace bolt {
case TypeKind::Tuple:
new (&Tuple)TTuple(std::move(Other.Tuple));
break;
case TypeKind::TupleIndex:
new (&TupleIndex)TTupleIndex(std::move(Other.TupleIndex));
break;
case TypeKind::Nil:
new (&Nil)TNil(std::move(Other.Nil));
break;
@ -492,20 +426,6 @@ namespace bolt {
return Tuple;
}
bool isTupleIndex() const {
return Kind == TypeKind::TupleIndex;
}
TTupleIndex& asTupleIndex() {
ZEN_ASSERT(Kind == TypeKind::TupleIndex);
return TupleIndex;
}
const TTupleIndex& asTupleIndex() const {
ZEN_ASSERT(Kind == TypeKind::TupleIndex);
return TupleIndex;
}
bool isField() const {
return Kind == TypeKind::Field;
}
@ -611,9 +531,6 @@ namespace bolt {
case TypeKind::Tuple:
Tuple.~TTuple();
break;
case TypeKind::TupleIndex:
TupleIndex.~TTupleIndex();
break;
case TypeKind::Nil:
Nil.~TNil();
break;
@ -648,9 +565,6 @@ namespace bolt {
case TypeKind::Tuple:
Tuple = Other.Tuple;
break;
case TypeKind::TupleIndex:
TupleIndex = Other.TupleIndex;
break;
case TypeKind::Nil:
Nil = Other.Nil;
break;
@ -735,10 +649,6 @@ namespace bolt {
}
}
virtual void visitTupleIndexType(C<TTupleIndex>& Ty) {
visit(Ty.Ty);
}
virtual void visitAbsentType(C<TAbsent>& Ty) {
}
@ -794,12 +704,6 @@ namespace bolt {
visit(Present->Ty);
break;
}
case TypeKind::TupleIndex:
{
auto& Index = Ty->asTupleIndex();
visit(Index->Ty);
break;
}
}
}
@ -837,9 +741,6 @@ namespace bolt {
case TypeKind::App:
visitAppType(Ty->asApp());
break;
case TypeKind::TupleIndex:
visitTupleIndexType(Ty->asTupleIndex());
break;
}
exitType(Ty);
}

View file

@ -30,37 +30,20 @@ namespace bolt {
}
return new CMany(*NewConstraints);
}
case ConstraintKind::Field:
{
auto Field = static_cast<CField*>(this);
auto NewTupleTy = Field->TupleTy->substitute(Sub);
auto NewFieldTy = Field->FieldTy->substitute(Sub);
return new CField(NewTupleTy, Field->I, NewFieldTy);
}
case ConstraintKind::Empty:
return this;
}
}
Type* Checker::simplifyType(Type* Ty) {
Ty = Ty->find();
if (Ty->isTupleIndex()) {
auto& Index = Ty->asTupleIndex();
auto MaybeTuple = simplifyType(Index.Ty);
if (MaybeTuple->isTuple()) {
auto& Tuple = MaybeTuple->asTuple();
if (Index.I >= Tuple.ElementTypes.size()) {
DE.add<TupleIndexOutOfRangeDiagnostic>(MaybeTuple, Index.I);
} else {
auto ElementTy = simplifyType(Tuple.ElementTypes[Index.I]);
Ty->set(ElementTy);
Ty = ElementTy;
}
} else if (!MaybeTuple->isVar()) {
DE.add<NotATupleDiagnostic>(MaybeTuple);
}
}
return Ty;
}
Type* Checker::solveType(Type* Ty) {
return Ty->rewrite([this](auto Ty) { return simplifyType(Ty); }, true);
return Ty->rewrite([this](auto Ty) { return Ty->find(); }, true);
}
Checker::Checker(const LanguageConfig& Config, DiagnosticEngine& DE):
@ -135,7 +118,14 @@ namespace bolt {
}
void Checker::addConstraint(Constraint* C) {
switch (C->getKind()) {
case ConstraintKind::Field:
// FIXME Check if this is all that needs to be done
getContext().Constraints->push_back(C);
break;
case ConstraintKind::Equal:
{
auto Y = static_cast<CEqual*>(C);
@ -195,13 +185,14 @@ namespace bolt {
}
if (UpperLevel == LowerLevel || MaxLevelLeft == Global || MaxLevelRight == Global) {
solveEqual(Y);
unify(Y->Left, Y->Right, Y->Source);
} else {
Contexts[UpperLevel]->Constraints->push_back(C);
}
break;
}
case ConstraintKind::Many:
{
auto Y = static_cast<CMany*>(C);
@ -210,9 +201,12 @@ namespace bolt {
}
break;
}
case ConstraintKind::Empty:
break;
}
}
void Checker::forwardDeclare(Node* X) {
@ -1061,7 +1055,8 @@ namespace bolt {
case NodeKind::IntegerLiteral:
{
auto I = static_cast<IntegerLiteral*>(Member->Name);
Ty = new Type(TTupleIndex(ExprTy, I->getInteger()));
Ty = createTypeVar();
addConstraint(new CField(ExprTy, I->asInt(), Ty, Member));
break;
}
case NodeKind::Identifier:
@ -1310,6 +1305,26 @@ namespace bolt {
case ConstraintKind::Empty:
break;
case ConstraintKind::Field:
{
auto Field = static_cast<CField*>(Constraint);
auto MaybeTuple = Field->TupleTy->find();
if (MaybeTuple->isTuple()) {
auto& Tuple = MaybeTuple->asTuple();
if (Field->I >= Tuple.ElementTypes.size()) {
DE.add<TupleIndexOutOfRangeDiagnostic>(MaybeTuple, Field->I, Field->Source);
} else {
auto ElementTy = Tuple.ElementTypes[Field->I];
unify(ElementTy, Field->FieldTy, Field->Source);
}
} else if (MaybeTuple->isVar()) {
// TODO Add logic for when tuple is a var
} else {
DE.add<NotATupleDiagnostic>(MaybeTuple, Field->Source);
}
break;
}
case ConstraintKind::Many:
{
auto Many = static_cast<CMany*>(Constraint);
@ -1321,7 +1336,8 @@ namespace bolt {
case ConstraintKind::Equal:
{
solveEqual(static_cast<CEqual*>(Constraint));
auto Equal = static_cast<CEqual*>(Constraint);
unify(Equal->Left, Equal->Right, Equal->Source);
break;
}
@ -1392,7 +1408,11 @@ namespace bolt {
struct Unifier {
Checker& C;
CEqual* Constraint;
// CEqual* Constraint;
Type* Left;
Type* Right;
Node* Source;
// Internal state used by the unifier
ByteString CurrentFieldName;
@ -1400,15 +1420,15 @@ namespace bolt {
TypePath RightPath;
Type* getLeft() const {
return Constraint->Left;
return Left;
}
Type* getRight() const {
return Constraint->Right;
return Right;
}
Node* getSource() const {
return Constraint->Source;
return Source;
}
bool unifyField(Type* A, Type* B, bool DidSwap);
@ -1416,7 +1436,7 @@ namespace bolt {
bool unify(Type* A, Type* B, bool DidSwap);
bool unify() {
return unify(Constraint->Left, Constraint->Right, false);
return unify(Left, Right, false);
}
std::vector<TypeclassContext> findInstanceContext(const TypeSig& Ty, TypeclassId& Class) {
@ -1548,16 +1568,16 @@ namespace bolt {
bool Unifier::unify(Type* A, Type* B, bool DidSwap) {
A = C.simplifyType(A);
B = C.simplifyType(B);
A = A->find();
B = B->find();
auto unifyError = [&]() {
C.DE.add<UnificationErrorDiagnostic>(
Constraint->Left,
Constraint->Right,
Left,
Right,
LeftPath,
RightPath,
Constraint->Source
Source
);
};
@ -1717,12 +1737,12 @@ namespace bolt {
return Success;
}
if (A->isTupleIndex() || B->isTupleIndex()) {
// Type(s) could not be simplified at the beginning of this function,
// so we have to re-visit the constraint when there is more information.
C.Queue.push_back(Constraint);
return true;
}
// if (A->isTupleIndex() || B->isTupleIndex()) {
// // Type(s) could not be simplified at the beginning of this function,
// // so we have to re-visit the constraint when there is more information.
// C.Queue.push_back(Constraint);
// return true;
// }
// This does not work because it ignores the indices
// if (A->isTupleIndex() && B->isTupleIndex()) {
@ -1806,9 +1826,9 @@ namespace bolt {
return false;
}
void Checker::solveEqual(CEqual* C) {
void Checker::unify(Type* Left, Type* Right, Node* Source) {
// std::cerr << describe(C->Left) << " ~ " << describe(C->Right) << std::endl;
Unifier A { *this, C };
Unifier A { *this, Left, Right, Source };
A.unify();
}

View file

@ -235,11 +235,6 @@ namespace bolt {
Out << ")";
return Out.str();
}
case TypeKind::TupleIndex:
{
auto Y = Ty->asTupleIndex();
return describe(Y.Ty) + "." + std::to_string(Y.I);
}
case TypeKind::Nil:
return "{}";
case TypeKind::Absent:
@ -617,14 +612,6 @@ namespace bolt {
W.write(")");
}
void visitTupleIndexType(const TTupleIndex& Ty) override {
Path.push_back(TypeIndex::forTupleIndexType());
visit(Ty.Ty);
Path.pop_back();
W.write(".");
W.write(Ty.I);
}
void visitNilType(const TNil& Ty) override {
W.write("{}");
}
@ -889,6 +876,9 @@ namespace bolt {
writeType(E.I);
write(" is out of range for tuple ");
writeType(E.Tuple);
write("\n\n");
writeNode(E.Source);
write("\n");
break;
}
@ -927,7 +917,9 @@ namespace bolt {
writePrefix(E);
write("the type ");
writeType(E.Ty);
write(" is not a tuple.\n");
write(" is not a tuple.\n\n");
writeNode(E.Source);
write("\n");
break;
}

View file

@ -4,6 +4,8 @@
#include <sys/wait.h>
#include <vector>
#include "zen/range.hpp"
namespace bolt {
bool TypeclassSignature::operator<(const TypeclassSignature& Other) const {
@ -60,10 +62,6 @@ namespace bolt {
return true;
}
bool TTupleIndex::operator==(const TTupleIndex& Other) const {
return *Ty == *Other.Ty && I == Other.I;
}
bool TNil::operator==(const TNil& Other) const {
return true;
}
@ -101,8 +99,6 @@ namespace bolt {
return Nil == Other.Nil;
case TypeKind::Tuple:
return Tuple == Other.Tuple;
case TypeKind::TupleIndex:
return TupleIndex == Other.TupleIndex;
case TypeKind::App:
return App == Other.App;
}
@ -145,11 +141,6 @@ namespace bolt {
Proc(Present.Ty);
break;
}
case TypeKind::TupleIndex:
{
Proc(TupleIndex.Ty);
break;
}
}
}
@ -190,12 +181,6 @@ namespace bolt {
}
return new Type(TApp(NewOp, NewArg));
}
case TypeKind::TupleIndex:
{
auto Tuple = Ty2->asTupleIndex();
auto NewTy = Tuple.Ty->rewrite(Fn, Recursive);
return NewTy != Tuple.Ty ? new Type(TTupleIndex(NewTy, Tuple.I)) : Ty2;
}
case TypeKind::Tuple:
{
auto Tuple = Ty2->asTuple();
@ -258,8 +243,6 @@ namespace bolt {
return this->asApp().Op;
case TypeIndexKind::AppArgType:
return this->asApp().Arg;
case TypeIndexKind::TupleIndexType:
return this->asTupleIndex().Ty;
case TypeIndexKind::TupleElement:
return this->asTuple().ElementTypes[Index.I];
case TypeIndexKind::ArrowParamType:
@ -336,8 +319,6 @@ namespace bolt {
}
}
return false;
case TypeKind::TupleIndex:
return TupleIndex.Ty->hasTypeVar(TV);
case TypeKind::Field:
return Field.Ty->hasTypeVar(TV) || Field.RestTy->hasTypeVar(TV);
case TypeKind::Arrow: