Make struct-declarations polymorphic
This commit is contained in:
parent
15f87ecc67
commit
5f373a9d13
3 changed files with 110 additions and 8 deletions
|
@ -482,7 +482,7 @@ abstract class SchemeBase {
|
||||||
class Forall extends SchemeBase {
|
class Forall extends SchemeBase {
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
public tvs: TVar[],
|
public typeVars: TVar[],
|
||||||
public constraints: Constraint[],
|
public constraints: Constraint[],
|
||||||
public type: Type,
|
public type: Type,
|
||||||
) {
|
) {
|
||||||
|
@ -599,7 +599,7 @@ export class Checker {
|
||||||
|
|
||||||
private instantiate(scheme: Scheme, node: Syntax | null): Type {
|
private instantiate(scheme: Scheme, node: Syntax | null): Type {
|
||||||
const sub = new TVSub();
|
const sub = new TVSub();
|
||||||
for (const tv of scheme.tvs) {
|
for (const tv of scheme.typeVars) {
|
||||||
sub.set(tv, this.createTypeVar());
|
sub.set(tv, this.createTypeVar());
|
||||||
}
|
}
|
||||||
for (const constraint of scheme.constraints) {
|
for (const constraint of scheme.constraints) {
|
||||||
|
@ -891,7 +891,7 @@ export class Checker {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public inferTypeExpression(node: TypeExpression): Type {
|
public inferTypeExpression(node: TypeExpression, introduceTypeVars = false): Type {
|
||||||
|
|
||||||
switch (node.kind) {
|
switch (node.kind) {
|
||||||
|
|
||||||
|
@ -907,6 +907,22 @@ export class Checker {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SyntaxKind.VarTypeExpression:
|
||||||
|
{
|
||||||
|
const scheme = this.lookup(node.name.text);
|
||||||
|
if (scheme === null) {
|
||||||
|
if (!introduceTypeVars) {
|
||||||
|
this.diagnostics.add(new BindingNotFoudDiagnostic(node.name.text, node.name));
|
||||||
|
}
|
||||||
|
const type = this.createTypeVar();
|
||||||
|
this.addBinding(node.name.text, new Forall([], [], type));
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
assert(scheme.typeVars.length === 0);
|
||||||
|
assert(scheme.constraints.length === 0);
|
||||||
|
return scheme.type;
|
||||||
|
}
|
||||||
|
|
||||||
case SyntaxKind.ArrowTypeExpression:
|
case SyntaxKind.ArrowTypeExpression:
|
||||||
{
|
{
|
||||||
const paramTypes = [];
|
const paramTypes = [];
|
||||||
|
@ -1129,6 +1145,7 @@ export class Checker {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SyntaxKind.EnumDeclaration:
|
||||||
case SyntaxKind.StructDeclaration:
|
case SyntaxKind.StructDeclaration:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1169,6 +1186,7 @@ export class Checker {
|
||||||
case SyntaxKind.IfStatement:
|
case SyntaxKind.IfStatement:
|
||||||
case SyntaxKind.ReturnStatement:
|
case SyntaxKind.ReturnStatement:
|
||||||
case SyntaxKind.ExpressionStatement:
|
case SyntaxKind.ExpressionStatement:
|
||||||
|
case SyntaxKind.EnumDeclaration:
|
||||||
case SyntaxKind.StructDeclaration:
|
case SyntaxKind.StructDeclaration:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1208,16 +1226,36 @@ export class Checker {
|
||||||
case SyntaxKind.ReturnStatement:
|
case SyntaxKind.ReturnStatement:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SyntaxKind.EnumDeclaration:
|
||||||
|
{
|
||||||
|
// TODO complete this
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case SyntaxKind.StructDeclaration:
|
case SyntaxKind.StructDeclaration:
|
||||||
{
|
{
|
||||||
|
const env = node.typeEnv = new TypeEnv(parentEnv);
|
||||||
|
const typeVars = new TVSet();
|
||||||
|
const constraints = new ConstraintSet();
|
||||||
|
const context: InferContext = {
|
||||||
|
constraints,
|
||||||
|
typeVars,
|
||||||
|
env,
|
||||||
|
returnType: null,
|
||||||
|
};
|
||||||
|
this.pushContext(context);
|
||||||
|
for (const varExpr of node.typeVars) {
|
||||||
|
env.add(varExpr.text, new Forall([], [], this.createTypeVar()));
|
||||||
|
}
|
||||||
const fields = new Map<string, Type>();
|
const fields = new Map<string, Type>();
|
||||||
if (node.members !== null) {
|
if (node.members !== null) {
|
||||||
for (const member of node.members) {
|
for (const member of node.members) {
|
||||||
fields.set(member.name.text, this.inferTypeExpression(member.typeExpr));
|
fields.set(member.name.text, this.inferTypeExpression(member.typeExpr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.popContext(context);
|
||||||
const type = new TRecord(node, fields);
|
const type = new TRecord(node, fields);
|
||||||
parentEnv.add(node.name.text, new Forall([], [], type));
|
parentEnv.add(node.name.text, new Forall(typeVars, constraints, type));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
50
src/cst.ts
50
src/cst.ts
|
@ -107,6 +107,7 @@ export const enum SyntaxKind {
|
||||||
// Type expressions
|
// Type expressions
|
||||||
ReferenceTypeExpression,
|
ReferenceTypeExpression,
|
||||||
ArrowTypeExpression,
|
ArrowTypeExpression,
|
||||||
|
VarTypeExpression,
|
||||||
|
|
||||||
// Patterns
|
// Patterns
|
||||||
BindPattern,
|
BindPattern,
|
||||||
|
@ -240,6 +241,7 @@ export class Scope {
|
||||||
case SyntaxKind.ReturnStatement:
|
case SyntaxKind.ReturnStatement:
|
||||||
case SyntaxKind.IfStatement:
|
case SyntaxKind.IfStatement:
|
||||||
break;
|
break;
|
||||||
|
case SyntaxKind.EnumDeclaration:
|
||||||
case SyntaxKind.StructDeclaration:
|
case SyntaxKind.StructDeclaration:
|
||||||
break;
|
break;
|
||||||
case SyntaxKind.LetDeclaration:
|
case SyntaxKind.LetDeclaration:
|
||||||
|
@ -411,6 +413,32 @@ abstract class SyntaxBase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function forEachChild(node: Syntax, callback: (node: Syntax) => void): void {
|
||||||
|
|
||||||
|
for (const key of Object.getOwnPropertyNames(node)) {
|
||||||
|
if (isIgnoredProperty(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
visitField((node as any)[key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function visitField(field: any): void {
|
||||||
|
if (field === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Array.isArray(field)) {
|
||||||
|
for (const element of field) {
|
||||||
|
visitField(element);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (field instanceof SyntaxBase) {
|
||||||
|
callback(field as Syntax);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
abstract class TokenBase extends SyntaxBase {
|
abstract class TokenBase extends SyntaxBase {
|
||||||
|
|
||||||
private endPos: TextPosition | null = null;
|
private endPos: TextPosition | null = null;
|
||||||
|
@ -939,9 +967,30 @@ export class ReferenceTypeExpression extends SyntaxBase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class VarTypeExpression extends SyntaxBase {
|
||||||
|
|
||||||
|
public readonly kind = SyntaxKind.VarTypeExpression;
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
public name: Identifier
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFirstToken(): Token {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getLastToken(): Token {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export type TypeExpression
|
export type TypeExpression
|
||||||
= ReferenceTypeExpression
|
= ReferenceTypeExpression
|
||||||
| ArrowTypeExpression
|
| ArrowTypeExpression
|
||||||
|
| VarTypeExpression
|
||||||
|
|
||||||
export class BindPattern extends SyntaxBase {
|
export class BindPattern extends SyntaxBase {
|
||||||
|
|
||||||
|
@ -1686,6 +1735,7 @@ export class StructDeclaration extends SyntaxBase {
|
||||||
public pubKeyword: PubKeyword | null,
|
public pubKeyword: PubKeyword | null,
|
||||||
public structKeyword: StructKeyword,
|
public structKeyword: StructKeyword,
|
||||||
public name: IdentifierAlt,
|
public name: IdentifierAlt,
|
||||||
|
public typeVars: Identifier[],
|
||||||
public members: StructDeclarationField[] | null,
|
public members: StructDeclarationField[] | null,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
|
@ -51,6 +51,7 @@ import {
|
||||||
EnumDeclarationStructElement,
|
EnumDeclarationStructElement,
|
||||||
EnumDeclaration,
|
EnumDeclaration,
|
||||||
EnumDeclarationTupleElement,
|
EnumDeclarationTupleElement,
|
||||||
|
VarTypeExpression,
|
||||||
} from "./cst"
|
} from "./cst"
|
||||||
import { Stream } from "./util";
|
import { Stream } from "./util";
|
||||||
|
|
||||||
|
@ -168,6 +169,11 @@ export class Parser {
|
||||||
public parsePrimitiveTypeExpression(): TypeExpression {
|
public parsePrimitiveTypeExpression(): TypeExpression {
|
||||||
const t0 = this.peekToken();
|
const t0 = this.peekToken();
|
||||||
switch (t0.kind) {
|
switch (t0.kind) {
|
||||||
|
case SyntaxKind.Identifier:
|
||||||
|
{
|
||||||
|
this.getToken();
|
||||||
|
return new VarTypeExpression(t0);
|
||||||
|
}
|
||||||
case SyntaxKind.IdentifierAlt:
|
case SyntaxKind.IdentifierAlt:
|
||||||
return this.parseReferenceTypeExpression();
|
return this.parseReferenceTypeExpression();
|
||||||
default:
|
default:
|
||||||
|
@ -288,6 +294,7 @@ export class Parser {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const t2 = this.peekToken();
|
const t2 = this.peekToken();
|
||||||
if (t2.kind === SyntaxKind.LineFoldEnd
|
if (t2.kind === SyntaxKind.LineFoldEnd
|
||||||
|
|| t2.kind === SyntaxKind.Comma
|
||||||
|| t2.kind === SyntaxKind.RParen
|
|| t2.kind === SyntaxKind.RParen
|
||||||
|| t2.kind === SyntaxKind.RBrace
|
|| t2.kind === SyntaxKind.RBrace
|
||||||
|| t2.kind === SyntaxKind.RBracket
|
|| t2.kind === SyntaxKind.RBracket
|
||||||
|
@ -481,10 +488,14 @@ export class Parser {
|
||||||
this.raiseParseError(t0, [ SyntaxKind.StructKeyword ]);
|
this.raiseParseError(t0, [ SyntaxKind.StructKeyword ]);
|
||||||
}
|
}
|
||||||
const name = this.expectToken(SyntaxKind.IdentifierAlt);
|
const name = this.expectToken(SyntaxKind.IdentifierAlt);
|
||||||
const t2 = this.peekToken()
|
let t2 = this.getToken();
|
||||||
|
const typeVars = [];
|
||||||
|
while (t2.kind === SyntaxKind.Identifier) {
|
||||||
|
typeVars.push(t2);
|
||||||
|
t2 = this.getToken();
|
||||||
|
}
|
||||||
let members = null;
|
let members = null;
|
||||||
if (t2.kind === SyntaxKind.BlockStart) {
|
if (t2.kind === SyntaxKind.BlockStart) {
|
||||||
this.getToken();
|
|
||||||
members = [];
|
members = [];
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const t3 = this.peekToken();
|
const t3 = this.peekToken();
|
||||||
|
@ -499,9 +510,12 @@ export class Parser {
|
||||||
const member = new StructDeclarationField(name, colon, typeExpr);
|
const member = new StructDeclarationField(name, colon, typeExpr);
|
||||||
members.push(member);
|
members.push(member);
|
||||||
}
|
}
|
||||||
|
t2 = this.getToken();
|
||||||
}
|
}
|
||||||
this.expectToken(SyntaxKind.LineFoldEnd);
|
if (t2.kind !== SyntaxKind.LineFoldEnd) {
|
||||||
return new StructDeclaration(pubKeyword, t0, name, members);
|
this.raiseParseError(t2, [ SyntaxKind.LineFoldEnd, SyntaxKind.BlockStart, SyntaxKind.Identifier ]);
|
||||||
|
}
|
||||||
|
return new StructDeclaration(pubKeyword, t0, name, typeVars, members);
|
||||||
}
|
}
|
||||||
|
|
||||||
private parsePatternStartingWithConstructor() {
|
private parsePatternStartingWithConstructor() {
|
||||||
|
|
Loading…
Reference in a new issue