Improve handing of struct/enum types and declarations
Also removes TNominal from the list of types because it is redundant w.r.t. TCon.
This commit is contained in:
parent
bd4ed57c46
commit
985e2d0652
6 changed files with 88 additions and 132 deletions
|
@ -201,6 +201,7 @@ program.command('verify', { hidden: true })
|
||||||
|
|
||||||
const uncaughtDiagnostics = new Set(diagnostics);
|
const uncaughtDiagnostics = new Set(diagnostics);
|
||||||
|
|
||||||
|
// TODO check comments that did not match any diagnostic
|
||||||
for (const [line, comment] of file.comments) {
|
for (const [line, comment] of file.comments) {
|
||||||
if (comment[0].kind === SyntaxKind.At && comment[1].kind === SyntaxKind.Identifier && comment[1].text === 'expect_diagnostic' && comment[2].kind === SyntaxKind.StringLiteral) {
|
if (comment[0].kind === SyntaxKind.At && comment[1].kind === SyntaxKind.Identifier && comment[1].text === 'expect_diagnostic' && comment[2].kind === SyntaxKind.StringLiteral) {
|
||||||
for (const diagnostic of uncaughtDiagnostics) {
|
for (const diagnostic of uncaughtDiagnostics) {
|
||||||
|
|
|
@ -31,7 +31,7 @@ import {
|
||||||
import { assert, assertNever, isEmpty, MultiMap, toStringTag, InspectFn, implementationLimitation } from "./util";
|
import { assert, assertNever, isEmpty, MultiMap, toStringTag, InspectFn, implementationLimitation } from "./util";
|
||||||
import { Analyser } from "./analysis";
|
import { Analyser } from "./analysis";
|
||||||
import { InspectOptions } from "util";
|
import { InspectOptions } from "util";
|
||||||
import { TypeKind, TApp, TArrow, TCon, TField, TNil, TNominal, TPresent, TTuple, TUniVar, TVSet, TVSub, Type, TypeBase, TAbsent, TRigidVar, TVar, TTupleIndex } from "./types";
|
import { TypeKind, TApp, TArrow, TCon, TField, TNil, TPresent, TTuple, TUniVar, TVSet, TVSub, Type, TypeBase, TAbsent, TRigidVar, TVar, TTupleIndex } from "./types";
|
||||||
import { CClass, CEmpty, CEqual, CMany, Constraint, ConstraintKind, ConstraintSet } from "./constraints";
|
import { CClass, CEmpty, CEqual, CMany, Constraint, ConstraintKind, ConstraintSet } from "./constraints";
|
||||||
|
|
||||||
// export class Qual {
|
// export class Qual {
|
||||||
|
@ -384,9 +384,9 @@ export class Checker {
|
||||||
private nextKindVarId = 0;
|
private nextKindVarId = 0;
|
||||||
private nextConTypeId = 0;
|
private nextConTypeId = 0;
|
||||||
|
|
||||||
private stringType = this.createTCon([], 'String');
|
private stringType = this.createTCon('String');
|
||||||
private intType = this.createTCon([], 'Int');
|
private intType = this.createTCon('Int');
|
||||||
private boolType = this.createTCon([], 'Bool');
|
private boolType = this.createTCon('Bool');
|
||||||
|
|
||||||
private contexts: InferContext[] = [];
|
private contexts: InferContext[] = [];
|
||||||
|
|
||||||
|
@ -436,8 +436,8 @@ export class Checker {
|
||||||
return this.boolType;
|
return this.boolType;
|
||||||
}
|
}
|
||||||
|
|
||||||
private createTCon(types: Type[], name: string): TCon {
|
private createTCon(name: string, node: Syntax | null = null): TCon {
|
||||||
return new TCon(this.nextConTypeId++, types, name);
|
return new TCon(this.nextConTypeId++, name, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
private createTypeVar(node: Syntax | null = null): TUniVar {
|
private createTypeVar(node: Syntax | null = null): TUniVar {
|
||||||
|
@ -1447,12 +1447,13 @@ export class Checker {
|
||||||
|
|
||||||
case SyntaxKind.StructExpression:
|
case SyntaxKind.StructExpression:
|
||||||
{
|
{
|
||||||
type = new TNil(node);
|
const fields = new Map<string, Type>();
|
||||||
|
const restType = new TNil(node);
|
||||||
for (const member of node.members) {
|
for (const member of node.members) {
|
||||||
switch (member.kind) {
|
switch (member.kind) {
|
||||||
case SyntaxKind.StructExpressionField:
|
case SyntaxKind.StructExpressionField:
|
||||||
{
|
{
|
||||||
type = new TField(member.name.text, new TPresent(this.inferExpression(member.expression)), type, node);
|
fields.set(member.name.text, this.inferExpression(member.expression));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SyntaxKind.PunnedStructExpressionField:
|
case SyntaxKind.PunnedStructExpressionField:
|
||||||
|
@ -1465,15 +1466,14 @@ export class Checker {
|
||||||
} else {
|
} else {
|
||||||
fieldType = this.instantiate(scheme, member);
|
fieldType = this.instantiate(scheme, member);
|
||||||
}
|
}
|
||||||
type = new TField(member.name.text, new TPresent(fieldType), type, node);
|
fields.set(member.name.text, fieldType);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unexpected ${member}`);
|
throw new Error(`Unexpected ${member}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// FIXME build a type rather than sorting it
|
type = TField.build(fields, restType);
|
||||||
type = TField.sort(type);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1644,21 +1644,22 @@ export class Checker {
|
||||||
this.inferBindings(pattern.pattern, type, typeVars, constraints);
|
this.inferBindings(pattern.pattern, type, typeVars, constraints);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// case SyntaxKind.NamedTuplePattern:
|
case SyntaxKind.NamedTuplePattern:
|
||||||
// {
|
{
|
||||||
// const scheme = this.lookup(pattern.name, Symkind.Type);
|
const scheme = this.lookup(pattern.name, Symkind.Var);
|
||||||
// if (scheme === null) {
|
if (scheme === null) {
|
||||||
// return this.createTypeVar();
|
return;
|
||||||
// }
|
}
|
||||||
// let tupleType = new TTuple(pattern.elements.map(p =>
|
const ctorType = this.instantiate(scheme, pattern);
|
||||||
// this.inferBindings(p, this.createTypeVar(), typeVars, constraints));
|
let elementTypes = [];
|
||||||
// // FIXME not tested
|
for (const element of pattern.elements) {
|
||||||
// this.addConstraint(new CEqual(tupleType, type, pattern));
|
const tv = this.createTypeVar();
|
||||||
// return TApp.build(
|
this.inferBindings(element, tv, typeVars, constraints, generalize);
|
||||||
// new TNominal(scheme.type.node as StructDeclaration | EnumDeclaration, pattern),
|
elementTypes.push(tv);
|
||||||
// tupleType
|
}
|
||||||
// );
|
this.addConstraint(new CEqual(TArrow.build(elementTypes, type), ctorType, pattern));
|
||||||
// }
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case SyntaxKind.LiteralPattern:
|
case SyntaxKind.LiteralPattern:
|
||||||
{
|
{
|
||||||
|
@ -1693,13 +1694,14 @@ export class Checker {
|
||||||
case SyntaxKind.StructPattern:
|
case SyntaxKind.StructPattern:
|
||||||
{
|
{
|
||||||
const variadicMember = getVariadicMember(pattern);
|
const variadicMember = getVariadicMember(pattern);
|
||||||
let structType: Type;
|
const fields = new Map<string, Type>();
|
||||||
|
let restType: Type;
|
||||||
if (variadicMember === null) {
|
if (variadicMember === null) {
|
||||||
structType = new TNil(pattern);
|
restType = new TNil(pattern);
|
||||||
} else {
|
} else {
|
||||||
structType = this.createTypeVar();
|
restType = this.createTypeVar();
|
||||||
if (variadicMember.pattern !== null) {
|
if (variadicMember.pattern !== null) {
|
||||||
this.inferBindings(variadicMember.pattern, structType, typeVars, constraints);
|
this.inferBindings(variadicMember.pattern, restType, typeVars, constraints);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const member of pattern.members) {
|
for (const member of pattern.members) {
|
||||||
|
@ -1708,14 +1710,14 @@ export class Checker {
|
||||||
{
|
{
|
||||||
const fieldType = this.createTypeVar();
|
const fieldType = this.createTypeVar();
|
||||||
this.inferBindings(member.pattern, fieldType, typeVars, constraints);
|
this.inferBindings(member.pattern, fieldType, typeVars, constraints);
|
||||||
structType = new TField(member.name.text, new TPresent(fieldType), structType, pattern);
|
fields.set(member.name.text, fieldType);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SyntaxKind.PunnedStructPatternField:
|
case SyntaxKind.PunnedStructPatternField:
|
||||||
{
|
{
|
||||||
const fieldType = this.createTypeVar();
|
const fieldType = this.createTypeVar();
|
||||||
this.addBinding(member.name.text, Forall.mono(fieldType), Symkind.Var);
|
this.addBinding(member.name.text, Forall.mono(fieldType), Symkind.Var);
|
||||||
structType = new TField(member.name.text, new TPresent(fieldType), structType, pattern);
|
fields.set(member.name.text, fieldType);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SyntaxKind.VariadicStructPatternElement:
|
case SyntaxKind.VariadicStructPatternElement:
|
||||||
|
@ -1727,7 +1729,7 @@ export class Checker {
|
||||||
this.addConstraint(
|
this.addConstraint(
|
||||||
new CEqual(
|
new CEqual(
|
||||||
type,
|
type,
|
||||||
TField.sort(structType),
|
TField.build(fields, restType),
|
||||||
pattern,
|
pattern,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -1820,15 +1822,20 @@ export class Checker {
|
||||||
constraints,
|
constraints,
|
||||||
returnType: null,
|
returnType: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
this.pushContext(context);
|
this.pushContext(context);
|
||||||
|
|
||||||
const kindArgs = [];
|
const kindArgs = [];
|
||||||
for (const name of node.varExps) {
|
for (const name of node.varExps) {
|
||||||
const kindArg = this.createTypeVar();
|
const kindArg = this.createTypeVar();
|
||||||
env.add(name.text, Forall.mono(kindArg), Symkind.Type);
|
env.add(name.text, Forall.mono(kindArg), Symkind.Type);
|
||||||
kindArgs.push(kindArg);
|
kindArgs.push(kindArg);
|
||||||
}
|
}
|
||||||
const type = TApp.build(new TNominal(node, node), kindArgs);
|
|
||||||
|
const type = this.createTCon(node.name.text, node);
|
||||||
|
const appliedType = TApp.build(type, kindArgs);
|
||||||
parentEnv.add(node.name.text, new Forall(typeVars, new CMany(constraints), type), Symkind.Type);
|
parentEnv.add(node.name.text, new Forall(typeVars, new CMany(constraints), type), Symkind.Type);
|
||||||
|
|
||||||
let elementTypes: Type[] = [];
|
let elementTypes: Type[] = [];
|
||||||
if (node.members !== null) {
|
if (node.members !== null) {
|
||||||
for (const member of node.members) {
|
for (const member of node.members) {
|
||||||
|
@ -1838,28 +1845,30 @@ export class Checker {
|
||||||
{
|
{
|
||||||
const argTypes = member.elements.map(el => this.inferTypeExpression(el, false));
|
const argTypes = member.elements.map(el => this.inferTypeExpression(el, false));
|
||||||
elementType = new TTuple(argTypes, member);
|
elementType = new TTuple(argTypes, member);
|
||||||
ctorType = TArrow.build(argTypes, type, member);
|
ctorType = TArrow.build(argTypes, appliedType, member);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SyntaxKind.EnumDeclarationStructElement:
|
case SyntaxKind.EnumDeclarationStructElement:
|
||||||
{
|
{
|
||||||
elementType = new TNil(member);
|
const restType = new TNil(member);
|
||||||
|
const fields = new Map<string, Type>();
|
||||||
for (const field of member.fields) {
|
for (const field of member.fields) {
|
||||||
elementType = new TField(field.name.text, new TPresent(this.inferTypeExpression(field.typeExpr, false)), elementType, member);
|
fields.set(field.name.text, this.inferTypeExpression(field.typeExpr, false));
|
||||||
}
|
}
|
||||||
elementType = TField.sort(elementType);
|
elementType = TField.build(fields, restType);
|
||||||
ctorType = new TArrow(elementType, type);
|
ctorType = new TArrow(elementType, appliedType, member);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unexpected ${member}`);
|
throw new Error(`Unexpected ${member}`);
|
||||||
}
|
}
|
||||||
// FIXME `typeVars` may contain too much irrelevant type variables
|
|
||||||
parentEnv.add(member.name.text, new Forall(typeVars, new CMany(constraints), ctorType), Symkind.Var);
|
parentEnv.add(member.name.text, new Forall(typeVars, new CMany(constraints), ctorType), Symkind.Var);
|
||||||
elementTypes.push(elementType);
|
elementTypes.push(elementType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.popContext(context);
|
this.popContext(context);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1906,15 +1915,18 @@ export class Checker {
|
||||||
env.add(varExpr.text, Forall.mono(kindArg), Symkind.Type);
|
env.add(varExpr.text, Forall.mono(kindArg), Symkind.Type);
|
||||||
kindArgs.push(kindArg);
|
kindArgs.push(kindArg);
|
||||||
}
|
}
|
||||||
let type: Type = new TNil(node);
|
const fields = new Map<string, Type>();
|
||||||
|
const restType = new TNil(node);
|
||||||
if (node.fields !== null) {
|
if (node.fields !== null) {
|
||||||
for (const field of node.fields) {
|
for (const field of node.fields) {
|
||||||
type = new TField(field.name.text, new TPresent(this.inferTypeExpression(field.typeExpr)), type, node);
|
fields.set(field.name.text, this.inferTypeExpression(field.typeExpr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const type = this.createTCon(node.name.text, node.name);
|
||||||
|
const recordType = TField.build(fields, restType);
|
||||||
this.popContext(context);
|
this.popContext(context);
|
||||||
parentEnv.add(node.name.text, new Forall(typeVars, new CMany(constraints), TField.sort(type)), Symkind.Type);
|
parentEnv.add(node.name.text, new Forall(typeVars, new CMany(constraints), type), Symkind.Type);
|
||||||
//parentEnv.add(node.name.text, new Forall(typeVars, constraints, new TArrow(type, TApp.build(type, kindArgs))), Symkind.Var);
|
parentEnv.add(node.name.text, new Forall(typeVars, new CMany(constraints), new TArrow(recordType, type)), Symkind.Var);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2186,18 +2198,8 @@ export class Checker {
|
||||||
|
|
||||||
if (left.kind === TypeKind.Con && right.kind === TypeKind.Con) {
|
if (left.kind === TypeKind.Con && right.kind === TypeKind.Con) {
|
||||||
if (left.id === right.id) {
|
if (left.id === right.id) {
|
||||||
assert(left.argTypes.length === right.argTypes.length);
|
TypeBase.join(left, right);
|
||||||
const count = left.argTypes.length;
|
return true;
|
||||||
let success = true;
|
|
||||||
for (let i = 0; i < count; i++) {
|
|
||||||
if (!this.unify(left.argTypes[i], right.argTypes[i], enableDiagnostics)) {
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (success) {
|
|
||||||
TypeBase.join(left, right);
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2246,13 +2248,6 @@ export class Checker {
|
||||||
return success
|
return success
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.kind === TypeKind.Nominal && right.kind === TypeKind.Nominal) {
|
|
||||||
if (left.decl === right.decl) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// fall through to error reporting
|
|
||||||
}
|
|
||||||
|
|
||||||
if (left.kind === TypeKind.App && right.kind === TypeKind.App) {
|
if (left.kind === TypeKind.App && right.kind === TypeKind.App) {
|
||||||
return this.unify(left.left, right.left, enableDiagnostics)
|
return this.unify(left.left, right.left, enableDiagnostics)
|
||||||
&& this.unify(left.right, right.right, enableDiagnostics);
|
&& this.unify(left.right, right.right, enableDiagnostics);
|
||||||
|
|
|
@ -470,11 +470,11 @@ abstract class TokenBase extends SyntaxBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public getFirstToken(): Token {
|
public getFirstToken(): Token {
|
||||||
throw new Error(`Trying to get the first token of an object that is a token itself.`);
|
return this as Token;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getLastToken(): Token {
|
public getLastToken(): Token {
|
||||||
throw new Error(`Trying to get the last token of an object that is a token itself.`);
|
return this as Token;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getRange(): TextRange {
|
public getRange(): TextRange {
|
||||||
|
|
|
@ -548,11 +548,7 @@ export function describeType(type: Type): string {
|
||||||
switch (type.kind) {
|
switch (type.kind) {
|
||||||
case TypeKind.Con:
|
case TypeKind.Con:
|
||||||
{
|
{
|
||||||
let out = type.displayName;
|
return type.displayName;
|
||||||
for (const argType of type.argTypes) {
|
|
||||||
out += ' ' + describeType(argType);
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
case TypeKind.UniVar:
|
case TypeKind.UniVar:
|
||||||
return 'a' + type.id;
|
return 'a' + type.id;
|
||||||
|
@ -575,10 +571,6 @@ export function describeType(type: Type): string {
|
||||||
}
|
}
|
||||||
case TypeKind.TupleIndex:
|
case TypeKind.TupleIndex:
|
||||||
return describeType(type.tupleType) + '.' + type.index;
|
return describeType(type.tupleType) + '.' + type.index;
|
||||||
case TypeKind.Nominal:
|
|
||||||
{
|
|
||||||
return type.decl.name.text;
|
|
||||||
}
|
|
||||||
case TypeKind.Field:
|
case TypeKind.Field:
|
||||||
{
|
{
|
||||||
let out = '{ ' + type.name + ': ' + describeType(type.type);
|
let out = '{ ' + type.name + ': ' + describeType(type.type);
|
||||||
|
@ -594,7 +586,7 @@ export function describeType(type: Type): string {
|
||||||
}
|
}
|
||||||
case TypeKind.App:
|
case TypeKind.App:
|
||||||
{
|
{
|
||||||
return describeType(type.right) + ' ' + describeType(type.left);
|
return describeType(type.left) + ' ' + describeType(type.right);
|
||||||
}
|
}
|
||||||
case TypeKind.Nil:
|
case TypeKind.Nil:
|
||||||
return '{}';
|
return '{}';
|
||||||
|
|
|
@ -163,6 +163,13 @@ export class Scanner extends BufferedStream<Token> {
|
||||||
if (c0 === '#') {
|
if (c0 === '#') {
|
||||||
const line = this.currPos.line;
|
const line = this.currPos.line;
|
||||||
this.getChar();
|
this.getChar();
|
||||||
|
for (;;) {
|
||||||
|
const c1 = this.peekChar();
|
||||||
|
if (!isWhiteSpace(c1) || c1 === '\n' || c1 === EOF) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.getChar();
|
||||||
|
}
|
||||||
let text = '';
|
let text = '';
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const c1 = this.getChar();
|
const c1 = this.getChar();
|
||||||
|
@ -171,8 +178,10 @@ export class Scanner extends BufferedStream<Token> {
|
||||||
}
|
}
|
||||||
text += c1;
|
text += c1;
|
||||||
}
|
}
|
||||||
const scanner = new Scanner(text, this.diagnostics, this.file, this.getCurrentPosition());
|
if (text[0] === '@') {
|
||||||
this.file.comments.set(line, scanner.getAll());
|
const scanner = new Scanner(text, this.diagnostics, this.file, this.getCurrentPosition());
|
||||||
|
this.file.comments.set(line, scanner.getAll());
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -283,7 +283,6 @@ export class TCon extends TypeBase {
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
public id: number,
|
public id: number,
|
||||||
public argTypes: Type[],
|
|
||||||
public displayName: string,
|
public displayName: string,
|
||||||
public node: Syntax | null = null,
|
public node: Syntax | null = null,
|
||||||
) {
|
) {
|
||||||
|
@ -291,35 +290,23 @@ export class TCon extends TypeBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public *getTypeVars(): Iterable<TVar> {
|
public *getTypeVars(): Iterable<TVar> {
|
||||||
for (const argType of this.argTypes) {
|
|
||||||
yield* argType.getTypeVars();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public shallowClone(): TCon {
|
public shallowClone(): TCon {
|
||||||
return new TCon(
|
return new TCon(
|
||||||
this.id,
|
this.id,
|
||||||
this.argTypes,
|
|
||||||
this.displayName,
|
this.displayName,
|
||||||
this.node,
|
this.node,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public substitute(sub: TVSub): Type {
|
public substitute(_sub: TVSub): Type {
|
||||||
let changed = false;
|
return this;
|
||||||
const newArgTypes = [];
|
|
||||||
for (const argType of this.argTypes) {
|
|
||||||
const newArgType = argType.substitute(sub);
|
|
||||||
if (newArgType !== argType) {
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
newArgTypes.push(newArgType);
|
|
||||||
}
|
|
||||||
return changed ? new TCon(this.id, newArgTypes, this.displayName, this.node) : this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public [toStringTag](_depth: number, options: InspectOptions, inspect: InspectFn) {
|
public [toStringTag](_depth: number, _options: InspectOptions, _inspect: InspectFn) {
|
||||||
return this.displayName + ' ' + this.argTypes.map(t => inspect(t, options)).join(' ');
|
return this.displayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -430,6 +417,14 @@ export class TField extends TypeBase {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static build(fields: Map<string, Type>, restType: Type): Type {
|
||||||
|
let out = restType;
|
||||||
|
for (const [name, type] of fields) {
|
||||||
|
out = new TField(name, new TPresent(type, type.node), out, type.node);
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
public static sort(type: Type): Type {
|
public static sort(type: Type): Type {
|
||||||
const fields = new Map<string, TField>();
|
const fields = new Map<string, TField>();
|
||||||
while (type.kind === TypeKind.Field) {
|
while (type.kind === TypeKind.Field) {
|
||||||
|
@ -481,7 +476,7 @@ export class TApp extends TypeBase {
|
||||||
|
|
||||||
public static build(resultType: Type, types: Type[], node: Syntax | null = null): Type {
|
public static build(resultType: Type, types: Type[], node: Syntax | null = null): Type {
|
||||||
for (let i = 0; i < types.length; i++) {
|
for (let i = 0; i < types.length; i++) {
|
||||||
resultType = new TApp(types[i], resultType, node);
|
resultType = new TApp(resultType, types[i], node);
|
||||||
}
|
}
|
||||||
return resultType;
|
return resultType;
|
||||||
}
|
}
|
||||||
|
@ -518,38 +513,6 @@ export class TApp extends TypeBase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TNominal extends TypeBase {
|
|
||||||
|
|
||||||
public readonly kind = TypeKind.Nominal;
|
|
||||||
|
|
||||||
public constructor(
|
|
||||||
public decl: StructDeclaration | EnumDeclaration,
|
|
||||||
public node: Syntax | null = null,
|
|
||||||
) {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
public *getTypeVars(): Iterable<TVar> {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public shallowClone(): Type {
|
|
||||||
return new TNominal(
|
|
||||||
this.decl,
|
|
||||||
this.node,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public substitute(_sub: TVSub): Type {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public [toStringTag]() {
|
|
||||||
return this.decl.name.text;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Type
|
export type Type
|
||||||
= TCon
|
= TCon
|
||||||
| TArrow
|
| TArrow
|
||||||
|
@ -557,7 +520,6 @@ export type Type
|
||||||
| TUniVar
|
| TUniVar
|
||||||
| TTuple
|
| TTuple
|
||||||
| TApp
|
| TApp
|
||||||
| TNominal
|
|
||||||
| TField
|
| TField
|
||||||
| TNil
|
| TNil
|
||||||
| TPresent
|
| TPresent
|
||||||
|
@ -586,9 +548,6 @@ export function typesEqual(a: Type, b: Type): boolean {
|
||||||
case TypeKind.Nil:
|
case TypeKind.Nil:
|
||||||
case TypeKind.Absent:
|
case TypeKind.Absent:
|
||||||
return true;
|
return true;
|
||||||
case TypeKind.Nominal:
|
|
||||||
assert(b.kind === TypeKind.Nominal);
|
|
||||||
return a.decl === b.decl;
|
|
||||||
case TypeKind.App:
|
case TypeKind.App:
|
||||||
assert(b.kind === TypeKind.App);
|
assert(b.kind === TypeKind.App);
|
||||||
return typesEqual(a.left, b.left) && typesEqual(a.right, b.right);
|
return typesEqual(a.left, b.left) && typesEqual(a.right, b.right);
|
||||||
|
|
Loading…
Reference in a new issue