2022-08-21 16:25:52 +02:00
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
// TODO Add list of CST variable names to TVar and unify them so that e.g. the typeclass checker may pick one when displaying a diagnostic
|
|
|
|
|
2023-05-22 11:54:52 +02:00
|
|
|
// TODO (maybe) make unficiation work like union-find in find()
|
2023-05-20 23:48:26 +02:00
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
// TODO remove Args in TCon and just use it as a constant
|
|
|
|
// TODO make TApp traversable with TupleIndex
|
|
|
|
|
2023-05-22 17:06:31 +02:00
|
|
|
// TODO make simplify() rewrite the types in-place such that a reference too (Bool, Int).0 becomes Bool
|
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
// TODO Add a check for datatypes that create infinite structures.
|
2023-05-22 17:06:31 +02:00
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
// TODO see if we can merge UnificationError diagnostics so that we get a list of **all** types that were wrong on a given node
|
2023-05-23 16:07:58 +02:00
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
#include <algorithm>
|
|
|
|
#include <iterator>
|
2022-08-21 16:25:52 +02:00
|
|
|
#include <stack>
|
2023-05-29 20:37:23 +02:00
|
|
|
#include <map>
|
2022-08-21 16:25:52 +02:00
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
#include "bolt/Type.hpp"
|
2022-08-21 16:25:52 +02:00
|
|
|
#include "zen/config.hpp"
|
2023-05-20 23:48:26 +02:00
|
|
|
#include "zen/range.hpp"
|
2022-08-21 16:25:52 +02:00
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
#include "bolt/CSTVisitor.hpp"
|
2023-05-24 19:38:04 +02:00
|
|
|
#include "bolt/DiagnosticEngine.hpp"
|
2023-05-20 23:48:26 +02:00
|
|
|
#include "bolt/Diagnostics.hpp"
|
2022-08-21 16:25:52 +02:00
|
|
|
#include "bolt/CST.hpp"
|
|
|
|
#include "bolt/Checker.hpp"
|
|
|
|
|
|
|
|
namespace bolt {
|
|
|
|
|
2022-08-25 19:04:25 +02:00
|
|
|
std::string describe(const Type* Ty);
|
2022-08-21 20:56:58 +02:00
|
|
|
|
2022-08-25 19:04:25 +02:00
|
|
|
Constraint* Constraint::substitute(const TVSub &Sub) {
|
|
|
|
switch (Kind) {
|
2023-05-20 23:48:26 +02:00
|
|
|
case ConstraintKind::Class:
|
|
|
|
{
|
|
|
|
auto Class = static_cast<CClass*>(this);
|
|
|
|
std::vector<Type*> NewTypes;
|
|
|
|
for (auto Ty: Class->Types) {
|
|
|
|
NewTypes.push_back(Ty->substitute(Sub));
|
|
|
|
}
|
|
|
|
return new CClass(Class->Name, NewTypes);
|
|
|
|
}
|
2022-08-25 19:04:25 +02:00
|
|
|
case ConstraintKind::Equal:
|
|
|
|
{
|
2023-05-08 19:57:24 +02:00
|
|
|
auto Equal = static_cast<CEqual*>(this);
|
|
|
|
return new CEqual(Equal->Left->substitute(Sub), Equal->Right->substitute(Sub), Equal->Source);
|
2022-08-25 19:04:25 +02:00
|
|
|
}
|
|
|
|
case ConstraintKind::Many:
|
|
|
|
{
|
2023-05-08 19:57:24 +02:00
|
|
|
auto Many = static_cast<CMany*>(this);
|
2022-08-25 19:04:25 +02:00
|
|
|
auto NewConstraints = new ConstraintSet();
|
2023-05-08 19:57:24 +02:00
|
|
|
for (auto Element: Many->Elements) {
|
2022-08-25 19:04:25 +02:00
|
|
|
NewConstraints->push_back(Element->substitute(Sub));
|
|
|
|
}
|
|
|
|
return new CMany(*NewConstraints);
|
|
|
|
}
|
|
|
|
case ConstraintKind::Empty:
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
Type* Checker::simplifyType(Type* Ty) {
|
|
|
|
|
|
|
|
return Ty->rewrite([&](auto Ty) {
|
|
|
|
|
|
|
|
if (Ty->getKind() == TypeKind::Var) {
|
|
|
|
Ty = static_cast<TVar*>(Ty)->find();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Ty->getKind() == TypeKind::TupleIndex) {
|
|
|
|
auto Index = static_cast<TTupleIndex*>(Ty);
|
|
|
|
auto MaybeTuple = simplifyType(Index->Ty);
|
|
|
|
if (MaybeTuple->getKind() == TypeKind::Tuple) {
|
|
|
|
auto Tuple = static_cast<TTuple*>(MaybeTuple);
|
|
|
|
if (Index->I >= Tuple->ElementTypes.size()) {
|
|
|
|
DE.add<TupleIndexOutOfRangeDiagnostic>(Tuple, Index->I);
|
|
|
|
} else {
|
|
|
|
Ty = simplifyType(Tuple->ElementTypes[Index->I]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Ty;
|
|
|
|
|
|
|
|
}, /*Recursive=*/true);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
Checker::Checker(const LanguageConfig& Config, DiagnosticEngine& DE):
|
|
|
|
Config(Config), DE(DE) {
|
2023-05-29 20:37:23 +02:00
|
|
|
BoolType = createConType("Bool");
|
|
|
|
IntType = createConType("Int");
|
|
|
|
StringType = createConType("String");
|
2022-08-26 22:10:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Scheme* Checker::lookup(ByteString Name) {
|
|
|
|
for (auto Iter = Contexts.rbegin(); Iter != Contexts.rend(); Iter++) {
|
|
|
|
auto Curr = *Iter;
|
2022-08-25 19:04:25 +02:00
|
|
|
auto Match = Curr->Env.find(Name);
|
|
|
|
if (Match != Curr->Env.end()) {
|
2023-05-20 23:48:26 +02:00
|
|
|
return Match->second;
|
2022-08-25 19:04:25 +02:00
|
|
|
}
|
|
|
|
}
|
2022-08-26 22:10:18 +02:00
|
|
|
return nullptr;
|
2022-08-25 19:04:25 +02:00
|
|
|
}
|
|
|
|
|
2022-08-26 22:10:18 +02:00
|
|
|
Type* Checker::lookupMono(ByteString Name) {
|
2022-08-25 19:04:25 +02:00
|
|
|
auto Scm = lookup(Name);
|
|
|
|
if (Scm == nullptr) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2023-05-20 23:48:26 +02:00
|
|
|
auto F = static_cast<Forall*>(Scm);
|
|
|
|
ZEN_ASSERT(F->TVs == nullptr || F->TVs->empty());
|
|
|
|
return F->Type;
|
2022-08-25 19:04:25 +02:00
|
|
|
}
|
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
void Checker::addBinding(ByteString Name, Scheme* Scm) {
|
2023-05-23 21:32:23 +02:00
|
|
|
Contexts.back()->Env.emplace(Name, Scm);
|
2022-08-25 19:04:25 +02:00
|
|
|
}
|
|
|
|
|
2022-08-26 22:10:18 +02:00
|
|
|
Type* Checker::getReturnType() {
|
|
|
|
auto Ty = Contexts.back()->ReturnType;
|
|
|
|
ZEN_ASSERT(Ty != nullptr);
|
|
|
|
return Ty;
|
2022-08-21 16:25:52 +02:00
|
|
|
}
|
|
|
|
|
2022-08-26 22:10:18 +02:00
|
|
|
static bool hasTypeVar(TVSet& Set, Type* Type) {
|
|
|
|
for (auto TV: Type->getTypeVars()) {
|
|
|
|
if (Set.count(TV)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
InferContext& Checker::getContext() {
|
|
|
|
ZEN_ASSERT(!Contexts.empty());
|
|
|
|
return *Contexts.back();
|
|
|
|
}
|
|
|
|
|
2023-05-08 19:57:24 +02:00
|
|
|
void Checker::addConstraint(Constraint* C) {
|
|
|
|
switch (C->getKind()) {
|
2023-05-20 23:48:26 +02:00
|
|
|
case ConstraintKind::Class:
|
|
|
|
{
|
|
|
|
Contexts.back()->Constraints->push_back(C);
|
|
|
|
break;
|
|
|
|
}
|
2022-08-26 22:10:18 +02:00
|
|
|
case ConstraintKind::Equal:
|
|
|
|
{
|
2023-05-08 19:57:24 +02:00
|
|
|
auto Y = static_cast<CEqual*>(C);
|
2023-05-23 16:07:58 +02:00
|
|
|
|
2023-05-23 21:50:00 +02:00
|
|
|
std::size_t MaxLevelLeft = 0;
|
2023-05-23 20:09:05 +02:00
|
|
|
for (std::size_t I = Contexts.size(); I-- > 0; ) {
|
|
|
|
auto Ctx = Contexts[I];
|
2023-05-23 21:50:00 +02:00
|
|
|
if (hasTypeVar(*Ctx->TVs, Y->Left)) {
|
|
|
|
MaxLevelLeft = I;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::size_t MaxLevelRight = 0;
|
|
|
|
for (std::size_t I = Contexts.size(); I-- > 0; ) {
|
|
|
|
auto Ctx = Contexts[I];
|
|
|
|
if (hasTypeVar(*Ctx->TVs, Y->Right)) {
|
|
|
|
MaxLevelRight = I;
|
2023-05-23 20:09:05 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2023-05-23 21:50:00 +02:00
|
|
|
auto MaxLevel = std::max(MaxLevelLeft, MaxLevelRight);
|
2023-05-23 20:09:05 +02:00
|
|
|
|
|
|
|
std::size_t MinLevel = MaxLevel;
|
|
|
|
for (std::size_t I = 0; I < Contexts.size(); I++) {
|
|
|
|
auto Ctx = Contexts[I];
|
|
|
|
if (hasTypeVar(*Ctx->TVs, Y->Left) || hasTypeVar(*Ctx->TVs, Y->Right)) {
|
|
|
|
MinLevel = I;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO detect if MaxLevelLeft == 0 or MaxLevelRight == 0
|
2023-05-23 21:50:00 +02:00
|
|
|
if (MaxLevel == MinLevel || MaxLevelLeft == 0 || MaxLevelRight == 0) {
|
2023-05-23 20:09:05 +02:00
|
|
|
solveCEqual(Y);
|
|
|
|
} else {
|
|
|
|
Contexts[MaxLevel]->Constraints->push_back(C);
|
|
|
|
}
|
|
|
|
|
2022-08-26 22:10:18 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ConstraintKind::Many:
|
|
|
|
{
|
2023-05-08 19:57:24 +02:00
|
|
|
auto Y = static_cast<CMany*>(C);
|
2022-08-26 22:10:18 +02:00
|
|
|
for (auto Element: Y->Elements) {
|
|
|
|
addConstraint(Element);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ConstraintKind::Empty:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
void Checker::addClass(TypeclassSignature Sig) {
|
|
|
|
getContext().Classes.push_back(Sig);
|
|
|
|
}
|
|
|
|
|
2022-08-26 22:10:18 +02:00
|
|
|
void Checker::forwardDeclare(Node* X) {
|
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
switch (X->getKind()) {
|
2022-08-26 22:10:18 +02:00
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
case NodeKind::ExpressionStatement:
|
|
|
|
case NodeKind::ReturnStatement:
|
|
|
|
case NodeKind::IfStatement:
|
2022-08-26 22:10:18 +02:00
|
|
|
break;
|
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
case NodeKind::SourceFile:
|
2022-08-26 22:10:18 +02:00
|
|
|
{
|
2023-05-08 19:57:24 +02:00
|
|
|
auto File = static_cast<SourceFile*>(X);
|
|
|
|
for (auto Element: File->Elements) {
|
2022-08-26 22:10:18 +02:00
|
|
|
forwardDeclare(Element) ;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
case NodeKind::ClassDeclaration:
|
|
|
|
{
|
|
|
|
auto Class = static_cast<ClassDeclaration*>(X);
|
|
|
|
for (auto TE: Class->TypeVars) {
|
2023-05-23 20:47:41 +02:00
|
|
|
auto TV = new TVarRigid(NextTypeVarId++, TE->Name->getCanonicalText());
|
2023-05-21 14:50:28 +02:00
|
|
|
TV->Contexts.emplace(Class->Name->getCanonicalText());
|
2023-05-20 23:48:26 +02:00
|
|
|
TE->setType(TV);
|
|
|
|
}
|
|
|
|
for (auto Element: Class->Elements) {
|
|
|
|
forwardDeclare(Element);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case NodeKind::InstanceDeclaration:
|
|
|
|
{
|
|
|
|
auto Decl = static_cast<InstanceDeclaration*>(X);
|
2023-05-21 20:14:41 +02:00
|
|
|
|
|
|
|
// Needed to set the associated Type on the CST node
|
|
|
|
for (auto TE: Decl->TypeExps) {
|
|
|
|
inferTypeExpression(TE);
|
|
|
|
}
|
|
|
|
|
2023-05-21 14:50:28 +02:00
|
|
|
auto Match = InstanceMap.find(Decl->Name->getCanonicalText());
|
2023-05-20 23:48:26 +02:00
|
|
|
if (Match == InstanceMap.end()) {
|
2023-05-21 14:50:28 +02:00
|
|
|
InstanceMap.emplace(Decl->Name->getCanonicalText(), std::vector { Decl });
|
2023-05-20 23:48:26 +02:00
|
|
|
} else {
|
|
|
|
Match->second.push_back(Decl);
|
|
|
|
}
|
2023-05-21 20:14:41 +02:00
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
for (auto Element: Decl->Elements) {
|
|
|
|
forwardDeclare(Element);
|
|
|
|
}
|
2023-05-21 20:14:41 +02:00
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case NodeKind::LetDeclaration:
|
2023-05-26 14:30:50 +02:00
|
|
|
// These declarations will be handled separately in check()
|
|
|
|
break;
|
2023-05-23 16:07:58 +02:00
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
case NodeKind::VariantDeclaration:
|
|
|
|
{
|
|
|
|
auto Decl = static_cast<VariantDeclaration*>(X);
|
|
|
|
|
|
|
|
auto& ParentCtx = getContext();
|
|
|
|
auto Ctx = createInferContext();
|
|
|
|
Contexts.push_back(Ctx);
|
|
|
|
|
|
|
|
std::vector<TVar*> Vars;
|
|
|
|
for (auto TE: Decl->TVs) {
|
|
|
|
auto TV = createRigidVar(TE->Name->getCanonicalText());
|
|
|
|
Ctx->TVs->emplace(TV);
|
|
|
|
Vars.push_back(TV);
|
|
|
|
}
|
|
|
|
|
|
|
|
Type* Ty = createConType(Decl->Name->getCanonicalText());
|
|
|
|
|
|
|
|
// Must be added early so we can create recursive types
|
|
|
|
ParentCtx.Env.emplace(Decl->Name->getCanonicalText(), new Forall(Ty));
|
|
|
|
|
|
|
|
for (auto Member: Decl->Members) {
|
|
|
|
switch (Member->getKind()) {
|
|
|
|
case NodeKind::TupleVariantDeclarationMember:
|
|
|
|
{
|
|
|
|
auto TupleMember = static_cast<TupleVariantDeclarationMember*>(Member);
|
|
|
|
auto RetTy = Ty;
|
|
|
|
for (auto Var: Vars) {
|
|
|
|
RetTy = new TApp(RetTy, Var);
|
|
|
|
}
|
|
|
|
std::vector<Type*> ParamTypes;
|
|
|
|
for (auto Element: TupleMember->Elements) {
|
|
|
|
ParamTypes.push_back(inferTypeExpression(Element));
|
|
|
|
}
|
|
|
|
ParentCtx.Env.emplace(TupleMember->Name->getCanonicalText(), new Forall(Ctx->TVs, Ctx->Constraints, new TArrow(ParamTypes, RetTy)));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NodeKind::RecordVariantDeclarationMember:
|
|
|
|
{
|
|
|
|
// TODO
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
ZEN_UNREACHABLE
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Contexts.pop_back();
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case NodeKind::RecordDeclaration:
|
|
|
|
{
|
|
|
|
auto Decl = static_cast<RecordDeclaration*>(X);
|
|
|
|
|
|
|
|
auto& ParentCtx = getContext();
|
|
|
|
auto Ctx = createInferContext();
|
|
|
|
Contexts.push_back(Ctx);
|
|
|
|
std::vector<TVar*> Vars;
|
|
|
|
for (auto TE: Decl->Vars) {
|
|
|
|
auto TV = createRigidVar(TE->Name->getCanonicalText());
|
|
|
|
Ctx->TVs->emplace(TV);
|
|
|
|
Vars.push_back(TV);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Name = Decl->Name->getCanonicalText();
|
|
|
|
auto Ty = createConType(Name);
|
|
|
|
|
|
|
|
// Must be added early so we can create recursive types
|
|
|
|
ParentCtx.Env.emplace(Name, new Forall(Ty));
|
|
|
|
|
|
|
|
// Corresponds to the logic of one branch of a VaraintDeclarationMember
|
|
|
|
Type* FieldsTy = new TNil();
|
|
|
|
for (auto Field: Decl->Fields) {
|
|
|
|
FieldsTy = new TField(Field->Name->getCanonicalText(), new TPresent(inferTypeExpression(Field->TypeExpression)), FieldsTy);
|
|
|
|
}
|
|
|
|
Type* RetTy = Ty;
|
|
|
|
for (auto TV: Vars) {
|
|
|
|
RetTy = new TApp(RetTy, TV);
|
|
|
|
}
|
|
|
|
Contexts.pop_back();
|
|
|
|
addBinding(Name, new Forall(Ctx->TVs, Ctx->Constraints, new TArrow({ FieldsTy }, RetTy)));
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-05-26 14:30:50 +02:00
|
|
|
default:
|
|
|
|
ZEN_UNREACHABLE
|
2023-05-20 23:48:26 +02:00
|
|
|
|
2023-05-26 14:30:50 +02:00
|
|
|
}
|
2023-05-21 20:33:06 +02:00
|
|
|
|
2023-05-26 14:30:50 +02:00
|
|
|
}
|
2023-05-21 20:33:06 +02:00
|
|
|
|
2023-05-26 14:30:50 +02:00
|
|
|
void Checker::forwardDeclareLetDeclaration(LetDeclaration* N, TVSet* TVs, ConstraintSet* Constraints) {
|
2023-05-21 20:33:06 +02:00
|
|
|
|
2023-05-26 14:30:50 +02:00
|
|
|
auto Let = static_cast<LetDeclaration*>(N);
|
|
|
|
bool IsFunc = !Let->Params.empty();
|
|
|
|
bool IsInstance = llvm::isa<InstanceDeclaration>(Let->Parent);
|
|
|
|
bool IsClass = llvm::isa<ClassDeclaration>(Let->Parent);
|
|
|
|
bool HasContext = IsFunc || IsInstance || IsClass;
|
2023-05-23 20:47:41 +02:00
|
|
|
|
2023-05-26 14:30:50 +02:00
|
|
|
if (HasContext) {
|
|
|
|
Let->Ctx = createInferContext(TVs, Constraints);
|
|
|
|
Contexts.push_back(Let->Ctx);
|
|
|
|
}
|
2023-05-21 20:14:41 +02:00
|
|
|
|
2023-05-26 14:30:50 +02:00
|
|
|
// If declaring a let-declaration inside a type class declaration,
|
|
|
|
// we need to mark that the let-declaration requires this class.
|
|
|
|
// This marking is set on the rigid type variables of the class, which
|
|
|
|
// are then added to this local type environment.
|
|
|
|
if (IsClass) {
|
|
|
|
auto Class = static_cast<ClassDeclaration*>(Let->Parent);
|
|
|
|
for (auto TE: Class->TypeVars) {
|
|
|
|
auto TV = llvm::cast<TVar>(TE->getType());
|
|
|
|
Let->Ctx->Env.emplace(TE->Name->getCanonicalText(), new Forall(TV));
|
|
|
|
Let->Ctx->TVs->emplace(TV);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Here we infer the primary type of the let declaration. If there's a
|
|
|
|
// type assert, that assert should be authoritative so we use that.
|
|
|
|
// Otherwise, the type is not further specified and we create a new
|
|
|
|
// unification variable.
|
|
|
|
Type* Ty;
|
|
|
|
if (Let->TypeAssert) {
|
|
|
|
Ty = inferTypeExpression(Let->TypeAssert->TypeExpression);
|
|
|
|
} else {
|
|
|
|
Ty = createTypeVar();
|
|
|
|
}
|
|
|
|
Let->Ty = Ty;
|
|
|
|
|
|
|
|
// If declaring a let-declaration inside a type instance declaration,
|
|
|
|
// we need to perform some work to make sure the type asserts of the
|
|
|
|
// corresponding let-declaration in the type class declaration are
|
|
|
|
// accounted for.
|
|
|
|
if (IsInstance) {
|
|
|
|
|
|
|
|
auto Instance = static_cast<InstanceDeclaration*>(Let->Parent);
|
|
|
|
auto Class = llvm::cast<ClassDeclaration>(Instance->getScope()->lookup({ {}, Instance->Name->getCanonicalText() }, SymbolKind::Class));
|
|
|
|
|
|
|
|
// The type asserts in the type class declaration might make use of
|
|
|
|
// the type parameters of the type class declaration, so it is
|
|
|
|
// important to make them available in the type environment. Moreover,
|
|
|
|
// we will be unifying them with the actual types declared in the
|
|
|
|
// instance declaration, so we keep track of them.
|
|
|
|
std::vector<TVar *> Params;
|
|
|
|
TVSub Sub;
|
|
|
|
for (auto TE: Class->TypeVars) {
|
|
|
|
auto TV = createTypeVar();
|
|
|
|
Sub.emplace(llvm::cast<TVar>(TE->getType()), TV);
|
|
|
|
Params.push_back(TV);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto SigLet = llvm::cast<LetDeclaration>(Class->getScope()->lookupDirect({ {}, llvm::cast<BindPattern>(Let->Pattern)->Name->getCanonicalText() }, SymbolKind::Var));
|
|
|
|
|
|
|
|
// It would be very strange if there was no type assert in the type
|
|
|
|
// class let-declaration but we rather not let the compiler crash if that happens.
|
|
|
|
if (SigLet->TypeAssert) {
|
|
|
|
addConstraint(new CEqual(Ty, inferTypeExpression(SigLet->TypeAssert->TypeExpression)->substitute(Sub), Let));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Here we do the actual unification of e.g. Eq a with Eq Bool. The
|
|
|
|
// unification variables we created previously will be unified with
|
|
|
|
// e.g. Bool, which causes the type assert to also collapse to e.g.
|
|
|
|
// Bool -> Bool -> Bool.
|
|
|
|
for (auto [Param, TE] : zen::zip(Params, Instance->TypeExps)) {
|
2023-05-29 20:37:23 +02:00
|
|
|
addConstraint(new CEqual(Param, TE->getType(), TE));
|
2023-05-26 14:30:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Let->Body) {
|
|
|
|
switch (Let->Body->getKind()) {
|
|
|
|
case NodeKind::LetExprBody:
|
|
|
|
break;
|
|
|
|
case NodeKind::LetBlockBody:
|
|
|
|
{
|
|
|
|
auto Block = static_cast<LetBlockBody*>(Let->Body);
|
|
|
|
if (IsFunc) {
|
|
|
|
Let->Ctx->ReturnType = createTypeVar();
|
|
|
|
}
|
|
|
|
for (auto Element: Block->Elements) {
|
|
|
|
forwardDeclare(Element);
|
2022-08-26 22:10:18 +02:00
|
|
|
}
|
2023-05-26 14:30:50 +02:00
|
|
|
break;
|
2022-08-26 22:10:18 +02:00
|
|
|
}
|
2023-05-26 14:30:50 +02:00
|
|
|
default:
|
|
|
|
ZEN_UNREACHABLE
|
|
|
|
}
|
|
|
|
}
|
2022-08-26 22:10:18 +02:00
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
Type* BindTy;
|
2023-05-26 14:30:50 +02:00
|
|
|
if (HasContext) {
|
|
|
|
Contexts.pop_back();
|
2023-05-29 20:37:23 +02:00
|
|
|
BindTy = inferPattern(Let->Pattern, Let->Ctx->Constraints, Let->Ctx->TVs);
|
2023-05-26 14:30:50 +02:00
|
|
|
} else {
|
2023-05-29 20:37:23 +02:00
|
|
|
BindTy = inferPattern(Let->Pattern);
|
2023-05-26 14:30:50 +02:00
|
|
|
}
|
2023-05-29 20:37:23 +02:00
|
|
|
addConstraint(new CEqual(BindTy, Ty, Let));
|
2022-08-26 22:10:18 +02:00
|
|
|
|
2023-05-26 14:30:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Checker::inferLetDeclaration(LetDeclaration* N) {
|
|
|
|
|
|
|
|
auto Decl = static_cast<LetDeclaration*>(N);
|
|
|
|
bool IsFunc = !Decl->Params.empty();
|
|
|
|
bool IsInstance = llvm::isa<InstanceDeclaration>(Decl->Parent);
|
|
|
|
bool IsClass = llvm::isa<ClassDeclaration>(Decl->Parent);
|
|
|
|
bool HasContext = IsFunc || IsInstance || IsClass;
|
|
|
|
|
|
|
|
if (HasContext) {
|
|
|
|
Contexts.push_back(Decl->Ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<Type*> ParamTypes;
|
|
|
|
Type* RetType;
|
|
|
|
|
|
|
|
for (auto Param: Decl->Params) {
|
|
|
|
// TODO incorporate Param->TypeAssert or make it a kind of pattern
|
2023-05-29 20:37:23 +02:00
|
|
|
ParamTypes.push_back(inferPattern(Param->Pattern));
|
2023-05-26 14:30:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Decl->Body) {
|
|
|
|
switch (Decl->Body->getKind()) {
|
|
|
|
case NodeKind::LetExprBody:
|
|
|
|
{
|
|
|
|
auto Expr = static_cast<LetExprBody*>(Decl->Body);
|
|
|
|
RetType = inferExpression(Expr->Expression);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NodeKind::LetBlockBody:
|
|
|
|
{
|
|
|
|
auto Block = static_cast<LetBlockBody*>(Decl->Body);
|
|
|
|
ZEN_ASSERT(HasContext);
|
|
|
|
RetType = Decl->Ctx->ReturnType;
|
|
|
|
for (auto Element: Block->Elements) {
|
|
|
|
infer(Element);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
ZEN_UNREACHABLE
|
2022-08-26 22:10:18 +02:00
|
|
|
}
|
2023-05-26 14:30:50 +02:00
|
|
|
} else {
|
|
|
|
RetType = createTypeVar();
|
|
|
|
}
|
2022-08-26 22:10:18 +02:00
|
|
|
|
2023-05-26 14:30:50 +02:00
|
|
|
if (HasContext) {
|
|
|
|
Contexts.pop_back();
|
|
|
|
}
|
2022-08-26 22:10:18 +02:00
|
|
|
|
2023-05-26 14:30:50 +02:00
|
|
|
if (IsFunc) {
|
|
|
|
addConstraint(new CEqual { Decl->Ty, new TArrow(ParamTypes, RetType), N });
|
|
|
|
} else {
|
|
|
|
// Declaration is a plain (typed) variable
|
|
|
|
addConstraint(new CEqual { Decl->Ty, RetType, N });
|
2022-08-25 23:04:09 +02:00
|
|
|
}
|
2022-08-21 20:56:58 +02:00
|
|
|
|
2022-08-26 22:10:18 +02:00
|
|
|
}
|
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
void Checker::infer(Node* N) {
|
2022-08-21 16:25:52 +02:00
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
switch (N->getKind()) {
|
2022-08-21 16:25:52 +02:00
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
case NodeKind::SourceFile:
|
2022-08-21 16:25:52 +02:00
|
|
|
{
|
2023-05-20 23:48:26 +02:00
|
|
|
auto File = static_cast<SourceFile*>(N);
|
2023-05-08 19:57:24 +02:00
|
|
|
for (auto Element: File->Elements) {
|
2022-08-26 22:10:18 +02:00
|
|
|
infer(Element);
|
2022-08-21 16:25:52 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
case NodeKind::ClassDeclaration:
|
2022-08-25 23:04:09 +02:00
|
|
|
{
|
2023-05-20 23:48:26 +02:00
|
|
|
auto Decl = static_cast<ClassDeclaration*>(N);
|
|
|
|
for (auto Element: Decl->Elements) {
|
|
|
|
infer(Element);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case NodeKind::InstanceDeclaration:
|
|
|
|
{
|
|
|
|
auto Decl = static_cast<InstanceDeclaration*>(N);
|
|
|
|
for (auto Element: Decl->Elements) {
|
|
|
|
infer(Element);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
case NodeKind::VariantDeclaration:
|
|
|
|
case NodeKind::RecordDeclaration:
|
|
|
|
// Nothing to do for a type-level declaration
|
|
|
|
break;
|
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
case NodeKind::IfStatement:
|
|
|
|
{
|
|
|
|
auto IfStmt = static_cast<IfStatement*>(N);
|
2023-05-08 19:57:24 +02:00
|
|
|
for (auto Part: IfStmt->Parts) {
|
2022-08-25 23:04:09 +02:00
|
|
|
if (Part->Test != nullptr) {
|
2022-08-26 22:10:18 +02:00
|
|
|
addConstraint(new CEqual { BoolType, inferExpression(Part->Test), Part->Test });
|
2022-08-25 23:04:09 +02:00
|
|
|
}
|
|
|
|
for (auto Element: Part->Elements) {
|
2022-08-26 22:10:18 +02:00
|
|
|
infer(Element);
|
2022-08-25 23:04:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
case NodeKind::LetDeclaration:
|
2022-08-21 16:25:52 +02:00
|
|
|
break;
|
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
case NodeKind::ReturnStatement:
|
2022-08-25 23:04:09 +02:00
|
|
|
{
|
2023-05-20 23:48:26 +02:00
|
|
|
auto RetStmt = static_cast<ReturnStatement*>(N);
|
2022-08-25 23:04:09 +02:00
|
|
|
Type* ReturnType;
|
2023-05-08 19:57:24 +02:00
|
|
|
if (RetStmt->Expression) {
|
2023-05-26 14:30:50 +02:00
|
|
|
addConstraint(new CEqual { inferExpression(RetStmt->Expression), getReturnType(), RetStmt->Expression });
|
2022-08-25 23:04:09 +02:00
|
|
|
} else {
|
|
|
|
ReturnType = new TTuple({});
|
2023-05-26 14:30:50 +02:00
|
|
|
addConstraint(new CEqual { new TTuple({}), getReturnType(), N });
|
2022-08-25 23:04:09 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2022-08-21 16:25:52 +02:00
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
case NodeKind::ExpressionStatement:
|
2022-08-21 16:25:52 +02:00
|
|
|
{
|
2023-05-20 23:48:26 +02:00
|
|
|
auto ExprStmt = static_cast<ExpressionStatement*>(N);
|
2023-05-08 19:57:24 +02:00
|
|
|
inferExpression(ExprStmt->Expression);
|
2022-08-21 16:25:52 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
ZEN_UNREACHABLE
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
TCon* Checker::createConType(ByteString Name) {
|
|
|
|
return new TCon(NextConTypeId++, Name);
|
|
|
|
}
|
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
TVarRigid* Checker::createRigidVar(ByteString Name) {
|
|
|
|
auto TV = new TVarRigid(NextTypeVarId++, Name);
|
|
|
|
Contexts.back()->TVs->emplace(TV);
|
|
|
|
return TV;
|
|
|
|
}
|
|
|
|
|
2022-08-26 22:10:18 +02:00
|
|
|
TVar* Checker::createTypeVar() {
|
2023-05-20 23:48:26 +02:00
|
|
|
auto TV = new TVar(NextTypeVarId++, VarKind::Unification);
|
|
|
|
Contexts.back()->TVs->emplace(TV);
|
2022-08-25 19:04:25 +02:00
|
|
|
return TV;
|
2022-08-21 16:25:52 +02:00
|
|
|
}
|
|
|
|
|
2023-05-26 14:30:50 +02:00
|
|
|
InferContext* Checker::createInferContext(TVSet* TVs, ConstraintSet* Constraints) {
|
2023-05-20 23:48:26 +02:00
|
|
|
auto Ctx = new InferContext;
|
|
|
|
Ctx->TVs = new TVSet;
|
|
|
|
Ctx->Constraints = new ConstraintSet;
|
|
|
|
return Ctx;
|
|
|
|
}
|
|
|
|
|
|
|
|
Type* Checker::instantiate(Scheme* Scm, Node* Source) {
|
2022-08-21 16:25:52 +02:00
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
switch (Scm->getKind()) {
|
2022-08-21 16:25:52 +02:00
|
|
|
|
|
|
|
case SchemeKind::Forall:
|
|
|
|
{
|
2023-05-20 23:48:26 +02:00
|
|
|
auto F = static_cast<Forall*>(Scm);
|
2022-08-25 19:04:25 +02:00
|
|
|
|
2022-08-21 16:25:52 +02:00
|
|
|
TVSub Sub;
|
2023-05-20 23:48:26 +02:00
|
|
|
for (auto TV: *F->TVs) {
|
|
|
|
auto Fresh = createTypeVar();
|
|
|
|
Fresh->Contexts = TV->Contexts;
|
|
|
|
Sub[TV] = Fresh;
|
2022-08-21 16:25:52 +02:00
|
|
|
}
|
2022-08-25 19:04:25 +02:00
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
for (auto Constraint: *F->Constraints) {
|
2022-08-25 19:04:25 +02:00
|
|
|
|
2022-08-26 22:10:18 +02:00
|
|
|
auto NewConstraint = Constraint->substitute(Sub);
|
2022-08-25 19:04:25 +02:00
|
|
|
|
2022-08-26 22:10:18 +02:00
|
|
|
// This makes error messages prettier by relating the typing failure
|
|
|
|
// to the call site rather than the definition.
|
|
|
|
if (NewConstraint->getKind() == ConstraintKind::Equal) {
|
2023-05-23 20:09:05 +02:00
|
|
|
static_cast<CEqual*>(NewConstraint)->Source = Source;
|
2022-08-25 19:04:25 +02:00
|
|
|
}
|
2022-08-26 22:10:18 +02:00
|
|
|
|
|
|
|
addConstraint(NewConstraint);
|
2022-08-25 19:04:25 +02:00
|
|
|
}
|
|
|
|
|
2023-05-23 21:29:27 +02:00
|
|
|
// Note the call to simplify? This is because constraints may have already
|
2023-05-23 20:09:05 +02:00
|
|
|
// been solved, with some unification variables being erased. To make
|
2023-05-23 21:29:27 +02:00
|
|
|
// sure we instantiate unification variables that are still in use
|
2023-05-23 20:09:05 +02:00
|
|
|
// we solve before substituting.
|
2023-05-29 20:37:23 +02:00
|
|
|
return simplifyType(F->Type)->substitute(Sub);
|
2022-08-21 16:25:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
Constraint* Checker::convertToConstraint(ConstraintExpression* C) {
|
|
|
|
switch (C->getKind()) {
|
|
|
|
case NodeKind::TypeclassConstraintExpression:
|
|
|
|
{
|
|
|
|
auto D = static_cast<TypeclassConstraintExpression*>(C);
|
|
|
|
std::vector<Type*> Types;
|
|
|
|
for (auto TE: D->TEs) {
|
|
|
|
Types.push_back(inferTypeExpression(TE));
|
|
|
|
}
|
2023-05-21 14:50:28 +02:00
|
|
|
return new CClass(D->Name->getCanonicalText(), Types);
|
2023-05-20 23:48:26 +02:00
|
|
|
}
|
|
|
|
case NodeKind::EqualityConstraintExpression:
|
|
|
|
{
|
|
|
|
auto D = static_cast<EqualityConstraintExpression*>(C);
|
|
|
|
return new CEqual(inferTypeExpression(D->Left), inferTypeExpression(D->Right), C);
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
ZEN_UNREACHABLE
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Type* Checker::inferTypeExpression(TypeExpression* N) {
|
2022-08-25 19:04:25 +02:00
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
switch (N->getKind()) {
|
2022-08-25 19:04:25 +02:00
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
case NodeKind::ReferenceTypeExpression:
|
2022-08-25 19:04:25 +02:00
|
|
|
{
|
2023-05-20 23:48:26 +02:00
|
|
|
auto RefTE = static_cast<ReferenceTypeExpression*>(N);
|
2023-05-29 20:37:23 +02:00
|
|
|
auto Scm = lookup(RefTE->Name->getCanonicalText());
|
|
|
|
Type* Ty;
|
|
|
|
if (Scm == nullptr) {
|
2023-05-27 23:15:45 +02:00
|
|
|
DE.add<BindingNotFoundDiagnostic>(RefTE->Name->getCanonicalText(), RefTE->Name);
|
2023-05-20 23:48:26 +02:00
|
|
|
Ty = createTypeVar();
|
2023-05-29 20:37:23 +02:00
|
|
|
} else {
|
|
|
|
Ty = instantiate(Scm, RefTE);
|
2023-05-20 23:48:26 +02:00
|
|
|
}
|
|
|
|
N->setType(Ty);
|
|
|
|
return Ty;
|
|
|
|
}
|
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
case NodeKind::AppTypeExpression:
|
|
|
|
{
|
|
|
|
auto AppTE = static_cast<AppTypeExpression*>(N);
|
|
|
|
Type* Ty = inferTypeExpression(AppTE->Op);
|
|
|
|
for (auto Arg: AppTE->Args) {
|
|
|
|
Ty = new TApp(Ty, inferTypeExpression(Arg));
|
|
|
|
}
|
|
|
|
return Ty;
|
|
|
|
}
|
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
case NodeKind::VarTypeExpression:
|
|
|
|
{
|
|
|
|
auto VarTE = static_cast<VarTypeExpression*>(N);
|
2023-05-21 14:50:28 +02:00
|
|
|
auto Ty = lookupMono(VarTE->Name->getCanonicalText());
|
2023-05-20 23:48:26 +02:00
|
|
|
if (Ty == nullptr) {
|
|
|
|
if (Config.typeVarsRequireForall()) {
|
2023-05-21 14:50:28 +02:00
|
|
|
DE.add<BindingNotFoundDiagnostic>(VarTE->Name->getCanonicalText(), VarTE->Name);
|
2023-05-20 23:48:26 +02:00
|
|
|
}
|
2023-05-21 14:50:28 +02:00
|
|
|
Ty = createRigidVar(VarTE->Name->getCanonicalText());
|
|
|
|
addBinding(VarTE->Name->getCanonicalText(), new Forall(Ty));
|
2022-08-25 19:04:25 +02:00
|
|
|
}
|
2023-05-29 20:37:23 +02:00
|
|
|
ZEN_ASSERT(Ty->getKind() == TypeKind::Var);
|
2023-05-20 23:48:26 +02:00
|
|
|
N->setType(Ty);
|
2023-05-29 20:37:23 +02:00
|
|
|
return static_cast<TVar*>(Ty);
|
2022-08-25 19:04:25 +02:00
|
|
|
}
|
|
|
|
|
2023-05-23 22:36:01 +02:00
|
|
|
case NodeKind::TupleTypeExpression:
|
|
|
|
{
|
|
|
|
auto TupleTE = static_cast<TupleTypeExpression*>(N);
|
|
|
|
std::vector<Type*> ElementTypes;
|
|
|
|
for (auto [TE, Comma]: TupleTE->Elements) {
|
|
|
|
ElementTypes.push_back(inferTypeExpression(TE));
|
|
|
|
}
|
|
|
|
auto Ty = new TTuple(ElementTypes);
|
|
|
|
N->setType(Ty);
|
|
|
|
return Ty;
|
|
|
|
}
|
|
|
|
|
|
|
|
case NodeKind::NestedTypeExpression:
|
|
|
|
{
|
|
|
|
auto NestedTE = static_cast<NestedTypeExpression*>(N);
|
|
|
|
auto Ty = inferTypeExpression(NestedTE->TE);
|
|
|
|
N->setType(Ty);
|
|
|
|
return Ty;
|
|
|
|
}
|
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
case NodeKind::ArrowTypeExpression:
|
2022-08-25 19:04:25 +02:00
|
|
|
{
|
2023-05-20 23:48:26 +02:00
|
|
|
auto ArrowTE = static_cast<ArrowTypeExpression*>(N);
|
2022-08-25 19:04:25 +02:00
|
|
|
std::vector<Type*> ParamTypes;
|
2023-05-08 19:57:24 +02:00
|
|
|
for (auto ParamType: ArrowTE->ParamTypes) {
|
2022-08-26 22:10:18 +02:00
|
|
|
ParamTypes.push_back(inferTypeExpression(ParamType));
|
2022-08-25 19:04:25 +02:00
|
|
|
}
|
2023-05-08 19:57:24 +02:00
|
|
|
auto ReturnType = inferTypeExpression(ArrowTE->ReturnType);
|
2022-08-26 22:10:18 +02:00
|
|
|
auto Ty = new TArrow(ParamTypes, ReturnType);
|
2023-05-20 23:48:26 +02:00
|
|
|
N->setType(Ty);
|
|
|
|
return Ty;
|
|
|
|
}
|
|
|
|
|
|
|
|
case NodeKind::QualifiedTypeExpression:
|
|
|
|
{
|
|
|
|
auto QTE = static_cast<QualifiedTypeExpression*>(N);
|
|
|
|
for (auto [C, Comma]: QTE->Constraints) {
|
|
|
|
addConstraint(convertToConstraint(C));
|
|
|
|
}
|
|
|
|
auto Ty = inferTypeExpression(QTE->TE);
|
|
|
|
N->setType(Ty);
|
2022-08-26 22:10:18 +02:00
|
|
|
return Ty;
|
2022-08-25 19:04:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
ZEN_UNREACHABLE
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2022-08-21 16:25:52 +02:00
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
Type* sortRow(Type* Ty) {
|
|
|
|
std::map<ByteString, TField*> Fields;
|
|
|
|
while (Ty->getKind() == TypeKind::Field) {
|
|
|
|
auto Field = static_cast<TField*>(Ty);
|
|
|
|
Fields.emplace(Field->Name, Field);
|
|
|
|
Ty = Field->RestTy;
|
|
|
|
}
|
|
|
|
for (auto [Name, Field]: Fields) {
|
|
|
|
Ty = new TField(Name, Field->Ty, Ty);
|
|
|
|
}
|
|
|
|
return Ty;
|
|
|
|
}
|
|
|
|
|
2022-08-26 22:10:18 +02:00
|
|
|
Type* Checker::inferExpression(Expression* X) {
|
2022-08-21 16:25:52 +02:00
|
|
|
|
2023-05-23 20:09:05 +02:00
|
|
|
Type* Ty;
|
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
switch (X->getKind()) {
|
2022-08-21 16:25:52 +02:00
|
|
|
|
2023-05-21 17:14:11 +02:00
|
|
|
case NodeKind::MatchExpression:
|
|
|
|
{
|
|
|
|
auto Match = static_cast<MatchExpression*>(X);
|
|
|
|
Type* ValTy;
|
|
|
|
if (Match->Value) {
|
|
|
|
ValTy = inferExpression(Match->Value);
|
|
|
|
} else {
|
|
|
|
ValTy = createTypeVar();
|
|
|
|
}
|
2023-05-23 20:09:05 +02:00
|
|
|
Ty = createTypeVar();
|
2023-05-21 17:14:11 +02:00
|
|
|
for (auto Case: Match->Cases) {
|
|
|
|
auto NewCtx = createInferContext();
|
|
|
|
Contexts.push_back(NewCtx);
|
2023-05-29 20:37:23 +02:00
|
|
|
auto PattTy = inferPattern(Case->Pattern);
|
|
|
|
addConstraint(new CEqual(PattTy, ValTy, X));
|
|
|
|
auto ExprTy = inferExpression(Case->Expression);
|
|
|
|
addConstraint(new CEqual(ExprTy, Ty, Case->Expression));
|
2023-05-21 17:14:11 +02:00
|
|
|
Contexts.pop_back();
|
|
|
|
}
|
|
|
|
if (!Match->Value) {
|
2023-05-23 20:09:05 +02:00
|
|
|
Ty = new TArrow({ ValTy }, Ty);
|
2023-05-21 17:14:11 +02:00
|
|
|
}
|
2023-05-23 20:09:05 +02:00
|
|
|
break;
|
2023-05-21 17:14:11 +02:00
|
|
|
}
|
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
case NodeKind::RecordExpression:
|
|
|
|
{
|
|
|
|
auto Record = static_cast<RecordExpression*>(X);
|
|
|
|
Ty = new TNil();
|
|
|
|
for (auto [Field, Comma]: Record->Fields) {
|
|
|
|
Ty = new TField(Field->Name->getCanonicalText(), new TPresent(inferExpression(Field->getExpression())), Ty);
|
|
|
|
}
|
|
|
|
Ty = sortRow(Ty);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
case NodeKind::ConstantExpression:
|
2022-08-21 16:25:52 +02:00
|
|
|
{
|
2023-05-08 19:57:24 +02:00
|
|
|
auto Const = static_cast<ConstantExpression*>(X);
|
2023-05-23 20:09:05 +02:00
|
|
|
Ty = inferLiteral(Const->Token);
|
|
|
|
break;
|
2022-08-21 16:25:52 +02:00
|
|
|
}
|
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
case NodeKind::ReferenceExpression:
|
2022-08-21 16:25:52 +02:00
|
|
|
{
|
2023-05-08 19:57:24 +02:00
|
|
|
auto Ref = static_cast<ReferenceExpression*>(X);
|
2023-05-21 00:25:01 +02:00
|
|
|
ZEN_ASSERT(Ref->ModulePath.empty());
|
2023-05-26 14:30:50 +02:00
|
|
|
auto Target = Ref->getScope()->lookup(Ref->getSymbolPath());
|
|
|
|
if (Target && llvm::isa<LetDeclaration>(Target)) {
|
|
|
|
auto Let = static_cast<LetDeclaration*>(Target);
|
|
|
|
if (Let->IsCycleActive) {
|
|
|
|
return Let->Ty;
|
|
|
|
}
|
2022-08-26 22:10:18 +02:00
|
|
|
}
|
2023-05-21 14:50:28 +02:00
|
|
|
auto Scm = lookup(Ref->Name->getCanonicalText());
|
2022-08-21 16:25:52 +02:00
|
|
|
if (Scm == nullptr) {
|
2023-05-21 14:50:28 +02:00
|
|
|
DE.add<BindingNotFoundDiagnostic>(Ref->Name->getCanonicalText(), Ref->Name);
|
2023-05-20 23:48:26 +02:00
|
|
|
return createTypeVar();
|
2022-08-21 16:25:52 +02:00
|
|
|
}
|
2023-05-23 20:09:05 +02:00
|
|
|
Ty = instantiate(Scm, X);
|
|
|
|
break;
|
2022-08-25 19:04:25 +02:00
|
|
|
}
|
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
case NodeKind::CallExpression:
|
2022-08-25 19:04:25 +02:00
|
|
|
{
|
2023-05-08 19:57:24 +02:00
|
|
|
auto Call = static_cast<CallExpression*>(X);
|
|
|
|
auto OpTy = inferExpression(Call->Function);
|
2023-05-23 20:09:05 +02:00
|
|
|
Ty = createTypeVar();
|
2022-08-25 19:04:25 +02:00
|
|
|
std::vector<Type*> ArgTypes;
|
2023-05-08 19:57:24 +02:00
|
|
|
for (auto Arg: Call->Args) {
|
2022-08-26 22:10:18 +02:00
|
|
|
ArgTypes.push_back(inferExpression(Arg));
|
2022-08-25 19:04:25 +02:00
|
|
|
}
|
2023-05-23 20:09:05 +02:00
|
|
|
addConstraint(new CEqual { OpTy, new TArrow(ArgTypes, Ty), X });
|
|
|
|
break;
|
2022-08-21 16:25:52 +02:00
|
|
|
}
|
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
case NodeKind::InfixExpression:
|
2022-08-21 16:25:52 +02:00
|
|
|
{
|
2023-05-08 19:57:24 +02:00
|
|
|
auto Infix = static_cast<InfixExpression*>(X);
|
|
|
|
auto Scm = lookup(Infix->Operator->getText());
|
2022-08-21 16:25:52 +02:00
|
|
|
if (Scm == nullptr) {
|
2023-05-08 19:57:24 +02:00
|
|
|
DE.add<BindingNotFoundDiagnostic>(Infix->Operator->getText(), Infix->Operator);
|
2023-05-20 23:48:26 +02:00
|
|
|
return createTypeVar();
|
2022-08-21 16:25:52 +02:00
|
|
|
}
|
2023-05-20 23:48:26 +02:00
|
|
|
auto OpTy = instantiate(Scm, Infix->Operator);
|
2023-05-23 22:34:21 +02:00
|
|
|
Ty = createTypeVar();
|
2022-08-21 16:25:52 +02:00
|
|
|
std::vector<Type*> ArgTys;
|
2023-05-08 19:57:24 +02:00
|
|
|
ArgTys.push_back(inferExpression(Infix->LHS));
|
|
|
|
ArgTys.push_back(inferExpression(Infix->RHS));
|
2023-05-23 20:09:05 +02:00
|
|
|
addConstraint(new CEqual { new TArrow(ArgTys, Ty), OpTy, X });
|
|
|
|
break;
|
2022-08-21 16:25:52 +02:00
|
|
|
}
|
|
|
|
|
2023-05-22 17:06:31 +02:00
|
|
|
case NodeKind::TupleExpression:
|
|
|
|
{
|
|
|
|
auto Tuple = static_cast<TupleExpression*>(X);
|
|
|
|
std::vector<Type*> Types;
|
|
|
|
for (auto [E, Comma]: Tuple->Elements) {
|
|
|
|
Types.push_back(inferExpression(E));
|
|
|
|
}
|
2023-05-23 20:09:05 +02:00
|
|
|
Ty = new TTuple(Types);
|
|
|
|
break;
|
2023-05-22 17:06:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
case NodeKind::MemberExpression:
|
|
|
|
{
|
|
|
|
auto Member = static_cast<MemberExpression*>(X);
|
2023-05-29 20:37:23 +02:00
|
|
|
auto ExprTy = inferExpression(Member->E);
|
2023-05-22 17:06:31 +02:00
|
|
|
switch (Member->Name->getKind()) {
|
|
|
|
case NodeKind::IntegerLiteral:
|
|
|
|
{
|
|
|
|
auto I = static_cast<IntegerLiteral*>(Member->Name);
|
2023-05-29 20:37:23 +02:00
|
|
|
Ty = new TTupleIndex(ExprTy, I->getInteger());
|
2023-05-23 20:09:05 +02:00
|
|
|
break;
|
2023-05-22 17:06:31 +02:00
|
|
|
}
|
|
|
|
case NodeKind::Identifier:
|
|
|
|
{
|
2023-05-29 20:37:23 +02:00
|
|
|
auto K = static_cast<Identifier*>(Member->Name);
|
|
|
|
Ty = createTypeVar();
|
|
|
|
auto RestTy = createTypeVar();
|
|
|
|
addConstraint(new CEqual(new TField(K->getCanonicalText(), Ty, RestTy), ExprTy, Member));
|
2023-05-22 17:06:31 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
ZEN_UNREACHABLE
|
|
|
|
}
|
2023-05-23 20:56:11 +02:00
|
|
|
break;
|
2023-05-22 17:06:31 +02:00
|
|
|
}
|
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
case NodeKind::NestedExpression:
|
2022-08-26 22:10:18 +02:00
|
|
|
{
|
2023-05-08 19:57:24 +02:00
|
|
|
auto Nested = static_cast<NestedExpression*>(X);
|
2023-05-23 20:09:05 +02:00
|
|
|
Ty = inferExpression(Nested->Inner);
|
|
|
|
break;
|
2022-08-26 22:10:18 +02:00
|
|
|
}
|
|
|
|
|
2022-08-21 16:25:52 +02:00
|
|
|
default:
|
|
|
|
ZEN_UNREACHABLE
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-05-23 20:09:05 +02:00
|
|
|
// Ty = find(Ty);
|
|
|
|
X->setType(Ty);
|
|
|
|
return Ty;
|
2022-08-21 16:25:52 +02:00
|
|
|
}
|
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
Type* Checker::inferPattern(
|
2023-05-20 23:48:26 +02:00
|
|
|
Pattern* Pattern,
|
|
|
|
ConstraintSet* Constraints,
|
|
|
|
TVSet* TVs
|
|
|
|
) {
|
2022-08-25 19:04:25 +02:00
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
switch (Pattern->getKind()) {
|
2022-08-25 19:04:25 +02:00
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
case NodeKind::BindPattern:
|
|
|
|
{
|
2023-05-21 17:36:44 +02:00
|
|
|
auto P = static_cast<BindPattern*>(Pattern);
|
2023-05-29 20:37:23 +02:00
|
|
|
auto Ty = createTypeVar();
|
|
|
|
addBinding(P->Name->getCanonicalText(), new Forall(TVs, Constraints, Ty));
|
|
|
|
return Ty;
|
|
|
|
}
|
|
|
|
|
|
|
|
case NodeKind::NamedPattern:
|
|
|
|
{
|
|
|
|
auto P = static_cast<NamedPattern*>(Pattern);
|
|
|
|
auto Scm = lookup(P->Name->getCanonicalText());
|
|
|
|
std::vector<Type*> ParamTypes;
|
|
|
|
for (auto P2: P->Patterns) {
|
|
|
|
ParamTypes.push_back(inferPattern(P2, Constraints, TVs));
|
|
|
|
}
|
|
|
|
if (!Scm) {
|
|
|
|
DE.add<BindingNotFoundDiagnostic>(P->Name->getCanonicalText(), P->Name);
|
|
|
|
return createTypeVar();
|
|
|
|
}
|
|
|
|
auto Ty = instantiate(Scm, P);
|
|
|
|
auto RetTy = createTypeVar();
|
|
|
|
addConstraint(new CEqual(Ty, new TArrow(ParamTypes, RetTy), P));
|
|
|
|
return RetTy;
|
|
|
|
}
|
|
|
|
|
|
|
|
case NodeKind::NestedPattern:
|
|
|
|
{
|
|
|
|
auto P = static_cast<NestedPattern*>(Pattern);
|
|
|
|
return inferPattern(P->P, Constraints, TVs);
|
2023-05-21 17:36:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
case NodeKind::LiteralPattern:
|
|
|
|
{
|
|
|
|
auto P = static_cast<LiteralPattern*>(Pattern);
|
2023-05-29 20:37:23 +02:00
|
|
|
return inferLiteral(P->Literal);
|
2023-05-20 23:48:26 +02:00
|
|
|
}
|
2022-08-25 19:04:25 +02:00
|
|
|
|
2023-05-21 00:25:01 +02:00
|
|
|
default:
|
2022-08-25 19:04:25 +02:00
|
|
|
ZEN_UNREACHABLE
|
|
|
|
|
|
|
|
}
|
2023-05-20 23:48:26 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-05-21 17:36:44 +02:00
|
|
|
Type* Checker::inferLiteral(Literal* L) {
|
|
|
|
Type* Ty;
|
|
|
|
switch (L->getKind()) {
|
|
|
|
case NodeKind::IntegerLiteral:
|
|
|
|
Ty = lookupMono("Int");
|
|
|
|
break;
|
|
|
|
case NodeKind::StringLiteral:
|
|
|
|
Ty = lookupMono("String");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ZEN_UNREACHABLE
|
|
|
|
}
|
|
|
|
ZEN_ASSERT(Ty != nullptr);
|
|
|
|
return Ty;
|
|
|
|
}
|
|
|
|
|
2023-05-26 14:30:50 +02:00
|
|
|
void Checker::populate(SourceFile* SF) {
|
|
|
|
|
|
|
|
struct Visitor : public CSTVisitor<Visitor> {
|
|
|
|
|
|
|
|
Graph<Node*>& RefGraph;
|
|
|
|
|
|
|
|
std::stack<Node*> Stack;
|
|
|
|
|
|
|
|
void visitLetDeclaration(LetDeclaration* N) {
|
|
|
|
RefGraph.addVertex(N);
|
|
|
|
Stack.push(N);
|
|
|
|
visitEachChild(N);
|
|
|
|
Stack.pop();
|
|
|
|
}
|
|
|
|
|
|
|
|
void visitReferenceExpression(ReferenceExpression* N) {
|
|
|
|
auto Y = static_cast<ReferenceExpression*>(N);
|
|
|
|
auto Def = Y->getScope()->lookup(Y->getSymbolPath());
|
|
|
|
// Name lookup failures will be reported directly in inferExpression().
|
|
|
|
// Parameters are clearly no let-decarations. They never have their own
|
|
|
|
// inference context, so we have to skip them.
|
|
|
|
if (Def == nullptr || Def->getKind() == NodeKind::Parameter) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ZEN_ASSERT(Def->getKind() == NodeKind::LetDeclaration || Def->getKind() == NodeKind::SourceFile);
|
|
|
|
RefGraph.addEdge(Stack.top(), Def);
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
RefGraph.addVertex(SF);
|
|
|
|
Visitor V { {}, RefGraph };
|
|
|
|
V.Stack.push(SF);
|
|
|
|
V.visit(SF);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
void Checker::checkTypeclassSigs(Node* N) {
|
|
|
|
|
|
|
|
struct LetVisitor : CSTVisitor<LetVisitor> {
|
|
|
|
|
|
|
|
Checker& C;
|
|
|
|
|
|
|
|
void visitLetDeclaration(LetDeclaration* Decl) {
|
|
|
|
|
2023-05-23 16:07:58 +02:00
|
|
|
// Only inspect those let-declarations that look like a function
|
|
|
|
if (Decl->Params.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-05-21 17:53:07 +02:00
|
|
|
// Will contain the type classes that were specified in the type assertion by the user.
|
|
|
|
// There might be some other signatures as well, but those are an implementation detail.
|
2023-05-20 23:48:26 +02:00
|
|
|
std::vector<TypeclassSignature> Expected;
|
2023-05-21 17:53:07 +02:00
|
|
|
|
|
|
|
// We must add the type class itself to Expected because in order for
|
|
|
|
// propagation to work the rigid type variables expect this class to be
|
|
|
|
// present even inside the current class. By adding it to Expected, we
|
|
|
|
// are effectively cancelling out the default behavior of requiring the
|
|
|
|
// presence of this type classes.
|
|
|
|
if (llvm::isa<ClassDeclaration>(Decl->Parent)) {
|
|
|
|
auto Class = llvm::cast<ClassDeclaration>(Decl->Parent);
|
|
|
|
std::vector<TVar *> Tys;
|
|
|
|
for (auto TE : Class->TypeVars) {
|
|
|
|
Tys.push_back(llvm::cast<TVar>(TE->getType()));
|
|
|
|
}
|
|
|
|
Expected.push_back(
|
|
|
|
TypeclassSignature{Class->Name->getCanonicalText(), Tys});
|
|
|
|
}
|
|
|
|
|
|
|
|
// Here we scan the type signature for type classes that user expects to be there.
|
|
|
|
if (Decl->TypeAssert != nullptr) {
|
|
|
|
if (llvm::isa<QualifiedTypeExpression>(Decl->TypeAssert->TypeExpression)) {
|
|
|
|
auto QTE = static_cast<QualifiedTypeExpression*>(Decl->TypeAssert->TypeExpression);
|
|
|
|
for (auto [C, Comma]: QTE->Constraints) {
|
|
|
|
if (llvm::isa<TypeclassConstraintExpression>(C)) {
|
|
|
|
auto TCE = static_cast<TypeclassConstraintExpression*>(C);
|
|
|
|
std::vector<TVar*> Tys;
|
|
|
|
for (auto TE: TCE->TEs) {
|
|
|
|
auto TV = TE->getType();
|
|
|
|
ZEN_ASSERT(llvm::isa<TVar>(TV));
|
|
|
|
Tys.push_back(static_cast<TVar*>(TV));
|
|
|
|
}
|
|
|
|
Expected.push_back(TypeclassSignature { TCE->Name->getCanonicalText(), Tys });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sort them lexically and remove any duplicates
|
2023-05-20 23:48:26 +02:00
|
|
|
std::sort(Expected.begin(), Expected.end());
|
|
|
|
Expected.erase(std::unique(Expected.begin(), Expected.end()), Expected.end());
|
|
|
|
|
2023-05-21 17:53:07 +02:00
|
|
|
// Will contain the type class signatures that our program inferred that
|
|
|
|
// at the very least should be present to make the body work.
|
2023-05-20 23:48:26 +02:00
|
|
|
std::vector<TypeclassSignature> Actual;
|
2023-05-21 17:53:07 +02:00
|
|
|
|
|
|
|
// This is ugly but it works. Scan all type variables local to this
|
|
|
|
// declaration and add the classes that they require to Actual.
|
2023-05-20 23:48:26 +02:00
|
|
|
for (auto Ty: *Decl->Ctx->TVs) {
|
2023-05-29 20:37:23 +02:00
|
|
|
auto S = Ty->solve();
|
2023-05-20 23:48:26 +02:00
|
|
|
if (llvm::isa<TVar>(S)) {
|
|
|
|
auto TV = static_cast<TVar*>(S);
|
|
|
|
for (auto Class: TV->Contexts) {
|
|
|
|
Actual.push_back(TypeclassSignature { Class, { TV } });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-05-21 17:53:07 +02:00
|
|
|
|
|
|
|
// Sort them lexically and remove any duplicates
|
2023-05-20 23:48:26 +02:00
|
|
|
std::sort(Actual.begin(), Actual.end());
|
|
|
|
Actual.erase(std::unique(Actual.begin(), Actual.end()), Actual.end());
|
|
|
|
|
2023-05-21 17:53:07 +02:00
|
|
|
auto ActualIter = Actual.begin();
|
|
|
|
auto ExpectedIter = Expected.begin();
|
2023-05-20 23:48:26 +02:00
|
|
|
|
2023-05-21 17:53:07 +02:00
|
|
|
for (; ActualIter != Actual.end() || ExpectedIter != Expected.end() ;) {
|
|
|
|
|
|
|
|
// Our program inferred no more type classes that should be present,
|
|
|
|
// yet Expected still did find a few that the user declared in a
|
|
|
|
// signature. No errors should be reported, and we can quit this loop.
|
|
|
|
if (ActualIter == Actual.end()) {
|
2023-05-20 23:48:26 +02:00
|
|
|
// TODO Maybe issue a warning that a type class went unused
|
|
|
|
break;
|
|
|
|
}
|
2023-05-21 17:53:07 +02:00
|
|
|
|
|
|
|
// There are no more type classes that were expected, so any remaining
|
|
|
|
// type classes in Actual will not have a corresponding signature.
|
|
|
|
// This should be reported as an error.
|
|
|
|
if (ExpectedIter == Expected.end()) {
|
|
|
|
for (; ActualIter != Actual.end(); ActualIter++) {
|
|
|
|
C.DE.add<TypeclassMissingDiagnostic>(*ActualIter, Decl);
|
2023-05-20 23:48:26 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2023-05-21 17:53:07 +02:00
|
|
|
|
|
|
|
// If ExpectedIter is already at Show, but ActualIter is still at Eq,
|
|
|
|
// then we clearly missed the Eq in ExpectedIter. This clearly is an
|
|
|
|
// error, since the user missed something in a type signature.
|
|
|
|
if (*ActualIter < *ExpectedIter) {
|
|
|
|
C.DE.add<TypeclassMissingDiagnostic>(*ActualIter, Decl);
|
|
|
|
ActualIter++;
|
2023-05-20 23:48:26 +02:00
|
|
|
continue;
|
|
|
|
}
|
2023-05-21 17:53:07 +02:00
|
|
|
|
|
|
|
// If ActualIter is Show but ExpectedIter is still Eq, then the user
|
|
|
|
// specified too much type classes in a type signature. This is no error,
|
|
|
|
// but it might be worthwhile to issue a warning.
|
|
|
|
if (*ExpectedIter < *ActualIter) {
|
2023-05-20 23:48:26 +02:00
|
|
|
// DE.add<TypeclassMissingDiagnostic>(It2->Name, Decl);
|
2023-05-21 17:53:07 +02:00
|
|
|
ExpectedIter++;
|
2023-05-20 23:48:26 +02:00
|
|
|
continue;
|
|
|
|
}
|
2023-05-21 17:53:07 +02:00
|
|
|
|
|
|
|
// Both type class signatures are equal, cancelling each other out.
|
|
|
|
ActualIter++;
|
|
|
|
ExpectedIter++;
|
2023-05-20 23:48:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
LetVisitor V { {}, *this };
|
|
|
|
V.visit(N);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
Type* Checker::getType(TypedNode *Node) {
|
|
|
|
return Node->getType()->solve();
|
|
|
|
}
|
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
void Checker::check(SourceFile *SF) {
|
|
|
|
auto RootContext = createInferContext();
|
|
|
|
Contexts.push_back(RootContext);
|
|
|
|
addBinding("String", new Forall(StringType));
|
|
|
|
addBinding("Int", new Forall(IntType));
|
|
|
|
addBinding("Bool", new Forall(BoolType));
|
|
|
|
addBinding("True", new Forall(BoolType));
|
|
|
|
addBinding("False", new Forall(BoolType));
|
2022-08-26 22:10:18 +02:00
|
|
|
auto A = createTypeVar();
|
2023-05-20 23:48:26 +02:00
|
|
|
addBinding("==", new Forall(new TVSet { A }, new ConstraintSet, new TArrow({ A, A }, BoolType)));
|
|
|
|
addBinding("+", new Forall(new TArrow({ IntType, IntType }, IntType)));
|
|
|
|
addBinding("-", new Forall(new TArrow({ IntType, IntType }, IntType)));
|
|
|
|
addBinding("*", new Forall(new TArrow({ IntType, IntType }, IntType)));
|
|
|
|
addBinding("/", new Forall(new TArrow({ IntType, IntType }, IntType)));
|
2023-05-26 14:30:50 +02:00
|
|
|
populate(SF);
|
2022-08-26 22:10:18 +02:00
|
|
|
forwardDeclare(SF);
|
2023-05-26 14:30:50 +02:00
|
|
|
auto SCCs = RefGraph.strongconnect();
|
|
|
|
for (auto Nodes: SCCs) {
|
|
|
|
if (Nodes.size() == 1 && llvm::isa<SourceFile>(Nodes[0])) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
auto TVs = new TVSet;
|
|
|
|
auto Constraints = new ConstraintSet;
|
|
|
|
for (auto N: Nodes) {
|
|
|
|
auto Decl = static_cast<LetDeclaration*>(N);
|
|
|
|
forwardDeclareLetDeclaration(Decl, TVs, Constraints);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (auto Nodes: SCCs) {
|
|
|
|
if (Nodes.size() == 1 && llvm::isa<SourceFile>(Nodes[0])) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (auto N: Nodes) {
|
|
|
|
auto Decl = static_cast<LetDeclaration*>(N);
|
|
|
|
Decl->IsCycleActive = true;
|
|
|
|
}
|
|
|
|
for (auto N: Nodes) {
|
|
|
|
auto Decl = static_cast<LetDeclaration*>(N);
|
|
|
|
inferLetDeclaration(Decl);
|
|
|
|
}
|
|
|
|
for (auto N: Nodes) {
|
|
|
|
auto Decl = static_cast<LetDeclaration*>(N);
|
|
|
|
Decl->IsCycleActive = false;
|
|
|
|
}
|
|
|
|
}
|
2022-08-26 22:10:18 +02:00
|
|
|
infer(SF);
|
|
|
|
Contexts.pop_back();
|
2023-05-29 20:37:23 +02:00
|
|
|
solve(new CMany(*RootContext->Constraints));
|
2023-05-20 23:48:26 +02:00
|
|
|
checkTypeclassSigs(SF);
|
2022-08-21 16:25:52 +02:00
|
|
|
}
|
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
void Checker::solve(Constraint* Constraint) {
|
2022-08-21 16:25:52 +02:00
|
|
|
|
2023-05-23 16:07:58 +02:00
|
|
|
Queue.push_back(Constraint);
|
2022-08-21 16:25:52 +02:00
|
|
|
|
|
|
|
while (!Queue.empty()) {
|
|
|
|
|
2023-05-23 16:07:58 +02:00
|
|
|
auto Constraint = Queue.front();
|
|
|
|
Queue.pop_front();
|
2022-08-21 16:25:52 +02:00
|
|
|
|
|
|
|
switch (Constraint->getKind()) {
|
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
case ConstraintKind::Class:
|
|
|
|
{
|
|
|
|
// TODO
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-08-21 16:25:52 +02:00
|
|
|
case ConstraintKind::Empty:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ConstraintKind::Many:
|
|
|
|
{
|
2023-05-08 19:57:24 +02:00
|
|
|
auto Many = static_cast<CMany*>(Constraint);
|
|
|
|
for (auto Constraint: Many->Elements) {
|
2023-05-23 16:07:58 +02:00
|
|
|
Queue.push_back(Constraint);
|
2022-08-21 16:25:52 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ConstraintKind::Equal:
|
|
|
|
{
|
2023-05-20 23:48:26 +02:00
|
|
|
solveCEqual(static_cast<CEqual*>(Constraint));
|
2022-08-21 16:25:52 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-05-20 23:48:26 +02:00
|
|
|
bool assignableTo(Type* A, Type* B) {
|
|
|
|
if (llvm::isa<TCon>(A) && llvm::isa<TCon>(B)) {
|
|
|
|
auto Con1 = llvm::cast<TCon>(A);
|
|
|
|
auto Con2 = llvm::cast<TCon>(B);
|
|
|
|
if (Con1->Id != Con2-> Id) {
|
|
|
|
return false;
|
|
|
|
}
|
2023-05-29 20:37:23 +02:00
|
|
|
// TODO must handle a TApp
|
|
|
|
// ZEN_ASSERT(Con1->Args.size() == Con2->Args.size());
|
|
|
|
// for (auto [T1, T2]: zen::zip(Con1->Args, Con2->Args)) {
|
|
|
|
// if (!assignableTo(T1, T2)) {
|
|
|
|
// return false;
|
|
|
|
// }
|
|
|
|
// }
|
2023-05-20 23:48:26 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
ZEN_UNREACHABLE
|
|
|
|
}
|
2022-08-21 16:25:52 +02:00
|
|
|
|
2023-05-22 22:37:58 +02:00
|
|
|
std::vector<TypeclassContext> Checker::findInstanceContext(TCon* Ty, TypeclassId& Class) {
|
2023-05-20 23:48:26 +02:00
|
|
|
auto Match = InstanceMap.find(Class);
|
|
|
|
std::vector<TypeclassContext> S;
|
|
|
|
if (Match != InstanceMap.end()) {
|
|
|
|
for (auto Instance: Match->second) {
|
|
|
|
if (assignableTo(Ty, Instance->TypeExps[0]->getType())) {
|
|
|
|
std::vector<TypeclassContext> S;
|
2023-05-29 20:37:23 +02:00
|
|
|
// TODO handle TApp
|
|
|
|
// for (auto Arg: Ty->Args) {
|
|
|
|
// TypeclassContext Classes;
|
|
|
|
// // TODO
|
|
|
|
// S.push_back(Classes);
|
|
|
|
// }
|
2023-05-20 23:48:26 +02:00
|
|
|
return S;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DE.add<InstanceNotFoundDiagnostic>(Class, Ty, Source);
|
2023-05-29 20:37:23 +02:00
|
|
|
// TODO handle TApp
|
|
|
|
// for (auto Arg: Ty->Args) {
|
|
|
|
// S.push_back({});
|
|
|
|
// }
|
2023-05-20 23:48:26 +02:00
|
|
|
return S;
|
|
|
|
}
|
|
|
|
|
2023-05-22 22:37:58 +02:00
|
|
|
void Checker::propagateClasses(std::unordered_set<TypeclassId>& Classes, Type* Ty) {
|
2023-05-20 23:48:26 +02:00
|
|
|
if (llvm::isa<TVar>(Ty)) {
|
|
|
|
auto TV = llvm::cast<TVar>(Ty);
|
|
|
|
for (auto Class: Classes) {
|
|
|
|
TV->Contexts.emplace(Class);
|
2022-08-21 16:25:52 +02:00
|
|
|
}
|
2023-05-20 23:48:26 +02:00
|
|
|
} else if (llvm::isa<TCon>(Ty)) {
|
|
|
|
for (auto Class: Classes) {
|
2023-05-22 22:37:58 +02:00
|
|
|
propagateClassTycon(Class, llvm::cast<TCon>(Ty));
|
2023-05-20 23:48:26 +02:00
|
|
|
}
|
2023-05-22 17:06:31 +02:00
|
|
|
} else if (!Classes.empty()) {
|
2023-05-24 14:11:59 +02:00
|
|
|
DE.add<InvalidTypeToTypeclassDiagnostic>(Ty, std::vector(Classes.begin(), Classes.end()), Source);
|
2022-08-21 16:25:52 +02:00
|
|
|
}
|
2023-05-20 23:48:26 +02:00
|
|
|
};
|
2022-08-21 16:25:52 +02:00
|
|
|
|
2023-05-22 22:37:58 +02:00
|
|
|
void Checker::propagateClassTycon(TypeclassId& Class, TCon* Ty) {
|
|
|
|
auto S = findInstanceContext(Ty, Class);
|
2023-05-29 20:37:23 +02:00
|
|
|
// TODO handle TApp
|
|
|
|
// for (auto [Classes, Arg]: zen::zip(S, Ty->Args)) {
|
|
|
|
// propagateClasses(Classes, Arg);
|
|
|
|
// }
|
2023-05-20 23:48:26 +02:00
|
|
|
};
|
|
|
|
|
2023-05-22 22:37:58 +02:00
|
|
|
void Checker::join(TVar* TV, Type* Ty) {
|
2023-05-22 17:06:31 +02:00
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
TV->set(Ty);
|
2023-05-22 17:06:31 +02:00
|
|
|
|
2023-05-22 22:37:58 +02:00
|
|
|
propagateClasses(TV->Contexts, Ty);
|
2023-05-22 17:06:31 +02:00
|
|
|
|
|
|
|
// This is a very specific adjustment that is critical to the
|
|
|
|
// well-functioning of the infer/unify algorithm. When addConstraint() is
|
|
|
|
// called, it may decide to solve the constraint immediately during
|
|
|
|
// inference. If this happens, a type variable might get assigned a concrete
|
|
|
|
// type such as Int. We therefore never want the variable to be polymorphic
|
2023-05-23 20:09:05 +02:00
|
|
|
// and be instantiated with a fresh variable, as that would allow Bool to
|
|
|
|
// collide with Int.
|
|
|
|
//
|
2023-05-22 17:06:31 +02:00
|
|
|
// Should it get assigned another unification variable, that's OK too
|
2023-05-23 20:09:05 +02:00
|
|
|
// because then that variable is what matters and it will become the new
|
|
|
|
// (possibly polymorphic) variable.
|
|
|
|
if (!Contexts.empty()) {
|
|
|
|
// std::cerr << "erase " << describe(TV) << std::endl;
|
|
|
|
auto TVs = Contexts.back()->TVs;
|
|
|
|
TVs->erase(TV);
|
|
|
|
}
|
2023-05-22 17:06:31 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-05-22 22:37:58 +02:00
|
|
|
class ArrowCursor {
|
|
|
|
|
|
|
|
std::stack<std::tuple<TArrow*, bool>> Stack;
|
|
|
|
TypePath& Path;
|
|
|
|
std::size_t I;
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
ArrowCursor(TArrow* Arr, TypePath& Path):
|
|
|
|
Path(Path) {
|
|
|
|
Stack.push({ Arr, true });
|
|
|
|
Path.push_back(Arr->getStartIndex());
|
2023-05-20 23:48:26 +02:00
|
|
|
}
|
2023-05-22 22:37:58 +02:00
|
|
|
|
|
|
|
Type* next() {
|
|
|
|
while (!Stack.empty()) {
|
|
|
|
auto& [Arrow, First] = Stack.top();
|
|
|
|
auto& Index = Path.back();
|
|
|
|
if (!First) {
|
|
|
|
Index.advance(Arrow);
|
|
|
|
} else {
|
|
|
|
First = false;
|
|
|
|
}
|
|
|
|
Type* Ty;
|
|
|
|
if (Index == Arrow->getEndIndex()) {
|
|
|
|
Path.pop_back();
|
|
|
|
Stack.pop();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
Ty = Arrow->resolve(Index);
|
|
|
|
if (llvm::isa<TArrow>(Ty)) {
|
|
|
|
auto NewIndex = Arrow->getStartIndex();
|
|
|
|
Stack.push({ static_cast<TArrow*>(Ty), true });
|
|
|
|
Path.push_back(NewIndex);
|
|
|
|
} else {
|
|
|
|
return Ty;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
struct Unifier {
|
2023-05-20 23:48:26 +02:00
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
Checker& C;
|
|
|
|
CEqual* Constraint;
|
2023-05-20 23:48:26 +02:00
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
// Internal state used by the unifier
|
|
|
|
ByteString CurrentFieldName;
|
|
|
|
TypePath LeftPath;
|
|
|
|
TypePath RightPath;
|
|
|
|
|
|
|
|
Type* getLeft() const {
|
|
|
|
return Constraint->Left;
|
|
|
|
}
|
|
|
|
|
|
|
|
Type* getRight() const {
|
|
|
|
return Constraint->Right;
|
|
|
|
}
|
|
|
|
|
|
|
|
Node* getSource() const {
|
|
|
|
return Constraint->Source;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool unify(Type* A, Type* B);
|
|
|
|
|
|
|
|
bool unifyField(Type* A, Type* B);
|
|
|
|
|
|
|
|
bool unify() {
|
|
|
|
return unify(Constraint->Left, Constraint->Right);
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
class UnificationFrame {
|
|
|
|
|
|
|
|
Unifier& U;
|
|
|
|
Type* A;
|
|
|
|
Type* B;
|
|
|
|
bool DidSwap = false;
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
UnificationFrame(Unifier& U, Type* A, Type* B):
|
|
|
|
U(U), A(U.C.simplifyType(A)), B(U.C.simplifyType(B)) {}
|
|
|
|
|
|
|
|
void unifyError() {
|
|
|
|
U.C.DE.add<UnificationErrorDiagnostic>(
|
|
|
|
U.C.simplifyType(U.Constraint->Left),
|
|
|
|
U.C.simplifyType(U.Constraint->Right),
|
|
|
|
U.LeftPath,
|
|
|
|
U.RightPath,
|
|
|
|
U.Constraint->Source
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
void pushLeft(TypeIndex I) {
|
|
|
|
if (DidSwap) {
|
|
|
|
U.RightPath.push_back(I);
|
|
|
|
} else {
|
|
|
|
U.LeftPath.push_back(I);
|
2023-05-20 23:48:26 +02:00
|
|
|
}
|
2023-05-29 20:37:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void popLeft() {
|
|
|
|
if (DidSwap) {
|
|
|
|
U.RightPath.pop_back();
|
2023-05-20 23:48:26 +02:00
|
|
|
} else {
|
2023-05-29 20:37:23 +02:00
|
|
|
U.LeftPath.pop_back();
|
2023-05-20 23:48:26 +02:00
|
|
|
}
|
2023-05-29 20:37:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void pushRight(TypeIndex I) {
|
|
|
|
if (DidSwap) {
|
|
|
|
U.LeftPath.push_back(I);
|
|
|
|
} else {
|
|
|
|
U.RightPath.push_back(I);
|
2023-05-26 14:30:50 +02:00
|
|
|
}
|
2023-05-20 23:48:26 +02:00
|
|
|
}
|
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
void popRight() {
|
|
|
|
if (DidSwap) {
|
|
|
|
U.LeftPath.pop_back();
|
|
|
|
} else {
|
|
|
|
U.RightPath.pop_back();
|
|
|
|
}
|
|
|
|
}
|
2023-05-22 22:37:58 +02:00
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
void swap() {
|
|
|
|
std::swap(A, B);
|
|
|
|
DidSwap = !DidSwap;
|
|
|
|
}
|
2023-05-22 22:37:58 +02:00
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
bool unifyField() {
|
|
|
|
if (llvm::isa<TAbsent>(A) && llvm::isa<TAbsent>(B)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (llvm::isa<TAbsent>(B)) {
|
|
|
|
swap();
|
|
|
|
}
|
|
|
|
if (llvm::isa<TAbsent>(A)) {
|
|
|
|
auto Present = static_cast<TPresent*>(B);
|
|
|
|
U.C.DE.add<FieldNotFoundDiagnostic>(U.CurrentFieldName, U.C.simplifyType(U.getLeft()), U.LeftPath, U.getSource());
|
2023-05-20 23:48:26 +02:00
|
|
|
return false;
|
|
|
|
}
|
2023-05-29 20:37:23 +02:00
|
|
|
auto Present1 = static_cast<TPresent*>(A);
|
|
|
|
auto Present2 = static_cast<TPresent*>(B);
|
|
|
|
return U.unify(Present1->Ty, Present2->Ty);
|
|
|
|
}
|
2023-05-22 22:37:58 +02:00
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
bool unify() {
|
|
|
|
|
|
|
|
if (llvm::isa<TVar>(A) && llvm::isa<TVar>(B)) {
|
|
|
|
auto Var1 = static_cast<TVar*>(A);
|
|
|
|
auto Var2 = static_cast<TVar*>(B);
|
|
|
|
if (Var1->getVarKind() == VarKind::Rigid && Var2->getVarKind() == VarKind::Rigid) {
|
|
|
|
if (Var1->Id != Var2->Id) {
|
|
|
|
unifyError();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
TVar* To;
|
|
|
|
TVar* From;
|
|
|
|
if (Var1->getVarKind() == VarKind::Rigid && Var2->getVarKind() == VarKind::Unification) {
|
|
|
|
To = Var1;
|
|
|
|
From = Var2;
|
|
|
|
} else {
|
|
|
|
// Only cases left are Var1 = Unification, Var2 = Rigid and Var1 = Unification, Var2 = Unification
|
|
|
|
// Either way, Var1, being Unification, is a good candidate for being unified away
|
|
|
|
To = Var2;
|
|
|
|
From = Var1;
|
|
|
|
}
|
|
|
|
if (From->Id != To->Id) {
|
|
|
|
U.C.join(From, To);
|
|
|
|
}
|
|
|
|
return true;
|
2022-08-21 16:25:52 +02:00
|
|
|
}
|
2023-05-22 22:37:58 +02:00
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
if (llvm::isa<TVar>(B)) {
|
|
|
|
swap();
|
|
|
|
}
|
2023-05-22 22:37:58 +02:00
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
if (llvm::isa<TVar>(A)) {
|
2022-08-21 16:25:52 +02:00
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
auto TV = static_cast<TVar*>(A);
|
2022-08-21 16:25:52 +02:00
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
// Rigid type variables can never unify with antything else than what we
|
|
|
|
// have already handled in the previous if-statement, so issue an error.
|
|
|
|
if (TV->getVarKind() == VarKind::Rigid) {
|
|
|
|
unifyError();
|
|
|
|
return false;
|
2023-05-20 23:48:26 +02:00
|
|
|
}
|
2023-05-29 20:37:23 +02:00
|
|
|
|
|
|
|
// Occurs check
|
|
|
|
if (B->hasTypeVar(TV)) {
|
|
|
|
// NOTE Just like GHC, we just display an error message indicating that
|
|
|
|
// A cannot match B, e.g. a cannot match [a]. It looks much better
|
|
|
|
// than obsure references to an occurs check
|
2023-05-22 22:37:58 +02:00
|
|
|
unifyError();
|
2023-05-29 20:37:23 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
U.C.join(TV, B);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (llvm::isa<TArrow>(A) && llvm::isa<TArrow>(B)) {
|
|
|
|
auto C1 = ArrowCursor(static_cast<TArrow*>(A), DidSwap ? U.RightPath : U.LeftPath);
|
|
|
|
auto C2 = ArrowCursor(static_cast<TArrow*>(B), DidSwap ? U.LeftPath : U.RightPath);
|
|
|
|
bool Success = true;
|
|
|
|
for (;;) {
|
|
|
|
auto T1 = C1.next();
|
|
|
|
auto T2 = C2.next();
|
|
|
|
if (T1 == nullptr && T2 == nullptr) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (T1 == nullptr || T2 == nullptr) {
|
|
|
|
unifyError();
|
|
|
|
Success = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!U.unify(T1, T2)) {
|
|
|
|
Success = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Success;
|
|
|
|
/* if (Arr1->ParamTypes.size() != Arr2->ParamTypes.size()) { */
|
|
|
|
/* return false; */
|
|
|
|
/* } */
|
|
|
|
/* auto Count = Arr1->ParamTypes.size(); */
|
|
|
|
/* for (std::size_t I = 0; I < Count; I++) { */
|
|
|
|
/* if (!unify(Arr1->ParamTypes[I], Arr2->ParamTypes[I], Solution)) { */
|
|
|
|
/* return false; */
|
|
|
|
/* } */
|
|
|
|
/* } */
|
|
|
|
/* return unify(Arr1->ReturnType, Arr2->ReturnType, Solution); */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (llvm::isa<TApp>(A) && llvm::isa<TApp>(B)) {
|
|
|
|
auto App1 = static_cast<TApp*>(A);
|
|
|
|
auto App2 = static_cast<TApp*>(B);
|
|
|
|
bool Success = true;
|
|
|
|
if (!U.unify(App1->Op, App2->Op)) {
|
2023-05-22 22:37:58 +02:00
|
|
|
Success = false;
|
2023-05-20 23:48:26 +02:00
|
|
|
}
|
2023-05-29 20:37:23 +02:00
|
|
|
if (!U.unify(App1->Arg, App2->Arg)) {
|
2023-05-22 22:37:58 +02:00
|
|
|
Success = false;
|
2022-08-21 16:25:52 +02:00
|
|
|
}
|
2023-05-29 20:37:23 +02:00
|
|
|
return Success;
|
2022-08-21 16:25:52 +02:00
|
|
|
}
|
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
if (llvm::isa<TArrow>(B)) {
|
|
|
|
swap();
|
2022-08-26 22:10:18 +02:00
|
|
|
}
|
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
if (llvm::isa<TArrow>(A)) {
|
|
|
|
auto Arr = static_cast<TArrow*>(A);
|
|
|
|
if (Arr->ParamTypes.empty()) {
|
|
|
|
auto Success = U.unify(Arr->ReturnType, B);
|
|
|
|
return Success;
|
|
|
|
}
|
|
|
|
}
|
2022-08-26 22:10:18 +02:00
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
if (llvm::isa<TTuple>(A) && llvm::isa<TTuple>(B)) {
|
|
|
|
auto Tuple1 = static_cast<TTuple*>(A);
|
|
|
|
auto Tuple2 = static_cast<TTuple*>(B);
|
|
|
|
if (Tuple1->ElementTypes.size() != Tuple2->ElementTypes.size()) {
|
|
|
|
unifyError();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
auto Count = Tuple1->ElementTypes.size();
|
|
|
|
bool Success = true;
|
|
|
|
for (size_t I = 0; I < Count; I++) {
|
|
|
|
U.LeftPath.push_back(TypeIndex::forTupleElement(I));
|
|
|
|
U.RightPath.push_back(TypeIndex::forTupleElement(I));
|
|
|
|
if (!U.unify(Tuple1->ElementTypes[I], Tuple2->ElementTypes[I])) {
|
|
|
|
Success = false;
|
|
|
|
}
|
|
|
|
U.LeftPath.pop_back();
|
|
|
|
U.RightPath.pop_back();
|
|
|
|
}
|
|
|
|
return Success;
|
2022-08-25 23:04:09 +02:00
|
|
|
}
|
2023-05-29 20:37:23 +02:00
|
|
|
|
|
|
|
if (llvm::isa<TTupleIndex>(A) || llvm::isa<TTupleIndex>(B)) {
|
|
|
|
// 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.
|
|
|
|
U.C.Queue.push_back(U.Constraint);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if (llvm::isa<TTupleIndex>(A) && llvm::isa<TTupleIndex>(B)) {
|
|
|
|
// auto Index1 = static_cast<TTupleIndex*>(A);
|
|
|
|
// auto Index2 = static_cast<TTupleIndex*>(B);
|
|
|
|
// return unify(Index1->Ty, Index2->Ty, Source);
|
|
|
|
// }
|
|
|
|
|
|
|
|
if (llvm::isa<TCon>(A) && llvm::isa<TCon>(B)) {
|
|
|
|
auto Con1 = static_cast<TCon*>(A);
|
|
|
|
auto Con2 = static_cast<TCon*>(B);
|
|
|
|
if (Con1->Id != Con2->Id) {
|
|
|
|
unifyError();
|
|
|
|
return false;
|
2022-08-25 23:04:09 +02:00
|
|
|
}
|
2023-05-29 20:37:23 +02:00
|
|
|
return true;
|
2022-08-25 23:04:09 +02:00
|
|
|
}
|
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
if (llvm::isa<TNil>(A) && llvm::isa<TNil>(B)) {
|
|
|
|
return true;
|
|
|
|
}
|
2023-05-23 16:07:58 +02:00
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
if (llvm::isa<TField>(A) && llvm::isa<TField>(B)) {
|
|
|
|
auto Field1 = static_cast<TField*>(A);
|
|
|
|
auto Field2 = static_cast<TField*>(B);
|
|
|
|
bool Success = true;
|
|
|
|
if (Field1->Name == Field2->Name) {
|
|
|
|
U.LeftPath.push_back(TypeIndex::forFieldType());
|
|
|
|
U.RightPath.push_back(TypeIndex::forFieldType());
|
|
|
|
U.CurrentFieldName = Field1->Name;
|
|
|
|
if (!U.unifyField(Field1->Ty, Field2->Ty)) {
|
|
|
|
Success = false;
|
|
|
|
}
|
|
|
|
U.LeftPath.pop_back();
|
|
|
|
U.RightPath.pop_back();
|
|
|
|
U.LeftPath.push_back(TypeIndex::forFieldRest());
|
|
|
|
U.RightPath.push_back(TypeIndex::forFieldRest());
|
|
|
|
if (!U.unify(Field1->RestTy, Field2->RestTy)) {
|
|
|
|
Success = false;
|
|
|
|
}
|
|
|
|
U.LeftPath.pop_back();
|
|
|
|
U.RightPath.pop_back();
|
|
|
|
return Success;
|
|
|
|
}
|
|
|
|
auto NewRestTy = new TVar(U.C.NextTypeVarId++, VarKind::Unification);
|
|
|
|
pushLeft(TypeIndex::forFieldRest());
|
|
|
|
if (!U.unify(Field1->RestTy, new TField(Field2->Name, Field2->Ty, NewRestTy))) {
|
|
|
|
Success = false;
|
|
|
|
}
|
|
|
|
popLeft();
|
|
|
|
pushRight(TypeIndex::forFieldRest());
|
|
|
|
if (!U.unify(new TField(Field1->Name, Field1->Ty, NewRestTy), Field2->RestTy)) {
|
|
|
|
Success = false;
|
|
|
|
}
|
|
|
|
popRight();
|
|
|
|
return Success;
|
|
|
|
}
|
2023-05-22 17:06:31 +02:00
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
if (llvm::isa<TNil>(A) && llvm::isa<TField>(B)) {
|
|
|
|
swap();
|
2022-08-21 16:25:52 +02:00
|
|
|
}
|
2023-05-29 20:37:23 +02:00
|
|
|
|
|
|
|
if (llvm::isa<TField>(A) && llvm::isa<TNil>(B)) {
|
|
|
|
auto Field = static_cast<TField*>(A);
|
|
|
|
bool Success = true;
|
|
|
|
pushLeft(TypeIndex::forFieldType());
|
|
|
|
U.CurrentFieldName = Field->Name;
|
|
|
|
if (!U.unifyField(Field->Ty, new TAbsent)) {
|
2023-05-22 22:37:58 +02:00
|
|
|
Success = false;
|
2022-08-21 16:25:52 +02:00
|
|
|
}
|
2023-05-29 20:37:23 +02:00
|
|
|
popLeft();
|
|
|
|
pushLeft(TypeIndex::forFieldRest());
|
|
|
|
if (!U.unify(Field->RestTy, B)) {
|
|
|
|
Success = false;
|
|
|
|
}
|
|
|
|
popLeft();
|
|
|
|
return Success;
|
2022-08-21 16:25:52 +02:00
|
|
|
}
|
2023-05-29 20:37:23 +02:00
|
|
|
|
|
|
|
unifyError();
|
|
|
|
return false;
|
2022-08-21 16:25:52 +02:00
|
|
|
}
|
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
bool Unifier::unify(Type* A, Type* B) {
|
|
|
|
UnificationFrame Frame { *this, A, B };
|
|
|
|
return Frame.unify();
|
2022-08-21 16:25:52 +02:00
|
|
|
}
|
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
bool Unifier::unifyField(Type* A, Type* B) {
|
|
|
|
UnificationFrame Frame { *this, A, B };
|
|
|
|
return Frame.unifyField();
|
2022-08-26 22:10:18 +02:00
|
|
|
}
|
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
void Checker::solveCEqual(CEqual* C) {
|
|
|
|
// std::cerr << describe(C->Left) << " ~ " << describe(C->Right) << std::endl;
|
|
|
|
Unifier A { *this, C };
|
|
|
|
A.unify();
|
2022-08-26 22:10:18 +02:00
|
|
|
}
|
|
|
|
|
2023-05-29 20:37:23 +02:00
|
|
|
|
2022-08-21 16:25:52 +02:00
|
|
|
}
|
|
|
|
|