Make type-checker catch all errors and update YAGL
This commit is contained in:
parent
469b0cc756
commit
cf5978c86c
4 changed files with 131 additions and 71 deletions
28
package-lock.json
generated
28
package-lock.json
generated
|
@ -11,21 +11,21 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"source-map-support": "^0.5.21",
|
"source-map-support": "^0.5.21",
|
||||||
"tslib": "^2.4.0",
|
"tslib": "^2.4.0",
|
||||||
"yagl": "^0.5.0",
|
"yagl": "^0.5.1",
|
||||||
"yargs": "^17.5.1"
|
"yargs": "^17.5.1"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"bolt": "lib/bin/bolt.js"
|
"bolt": "lib/bin/bolt.js"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^18.7.14",
|
"@types/node": "^18.7.15",
|
||||||
"@types/yargs": "^17.0.12"
|
"@types/yargs": "^17.0.12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "18.7.14",
|
"version": "18.7.15",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.14.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.15.tgz",
|
||||||
"integrity": "sha512-6bbDaETVi8oyIARulOE9qF1/Qdi/23z6emrUh0fNJRUmjznqrixD4MpGDdgOFk5Xb0m2H6Xu42JGdvAxaJR/wA==",
|
"integrity": "sha512-XnjpaI8Bgc3eBag2Aw4t2Uj/49lLBSStHWfqKvIuXD7FIrZyMLWp8KuAFHAqxMZYTF9l08N1ctUn9YNybZJVmQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/yargs": {
|
"node_modules/@types/yargs": {
|
||||||
|
@ -204,9 +204,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/yagl": {
|
"node_modules/yagl": {
|
||||||
"version": "0.5.0",
|
"version": "0.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/yagl/-/yagl-0.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/yagl/-/yagl-0.5.1.tgz",
|
||||||
"integrity": "sha512-nM6dkvVEgPkDdtNUmGdgvTyAwNnp88g8RvduiNewECU9mKDmazMFqSxkfK8gsvW/Zhzno7hzRHVlR6atFZk44g=="
|
"integrity": "sha512-DfJygWCefAq5eEOmwvVkiMFBUEQJs9aijGdhaYGSdj1TM2OqSbe/Vp37e/nMGXsgmWiryZapKMOtpYx3ECUrJQ=="
|
||||||
},
|
},
|
||||||
"node_modules/yargs": {
|
"node_modules/yargs": {
|
||||||
"version": "17.5.1",
|
"version": "17.5.1",
|
||||||
|
@ -236,9 +236,9 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "18.7.14",
|
"version": "18.7.15",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.14.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.15.tgz",
|
||||||
"integrity": "sha512-6bbDaETVi8oyIARulOE9qF1/Qdi/23z6emrUh0fNJRUmjznqrixD4MpGDdgOFk5Xb0m2H6Xu42JGdvAxaJR/wA==",
|
"integrity": "sha512-XnjpaI8Bgc3eBag2Aw4t2Uj/49lLBSStHWfqKvIuXD7FIrZyMLWp8KuAFHAqxMZYTF9l08N1ctUn9YNybZJVmQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/yargs": {
|
"@types/yargs": {
|
||||||
|
@ -375,9 +375,9 @@
|
||||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
|
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
|
||||||
},
|
},
|
||||||
"yagl": {
|
"yagl": {
|
||||||
"version": "0.5.0",
|
"version": "0.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/yagl/-/yagl-0.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/yagl/-/yagl-0.5.1.tgz",
|
||||||
"integrity": "sha512-nM6dkvVEgPkDdtNUmGdgvTyAwNnp88g8RvduiNewECU9mKDmazMFqSxkfK8gsvW/Zhzno7hzRHVlR6atFZk44g=="
|
"integrity": "sha512-DfJygWCefAq5eEOmwvVkiMFBUEQJs9aijGdhaYGSdj1TM2OqSbe/Vp37e/nMGXsgmWiryZapKMOtpYx3ECUrJQ=="
|
||||||
},
|
},
|
||||||
"yargs": {
|
"yargs": {
|
||||||
"version": "17.5.1",
|
"version": "17.5.1",
|
||||||
|
|
|
@ -24,11 +24,11 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"source-map-support": "^0.5.21",
|
"source-map-support": "^0.5.21",
|
||||||
"tslib": "^2.4.0",
|
"tslib": "^2.4.0",
|
||||||
"yagl": "^0.5.0",
|
"yagl": "^0.5.1",
|
||||||
"yargs": "^17.5.1"
|
"yargs": "^17.5.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^18.7.14",
|
"@types/node": "^18.7.15",
|
||||||
"@types/yargs": "^17.0.12"
|
"@types/yargs": "^17.0.12"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
161
src/checker.ts
161
src/checker.ts
|
@ -2,15 +2,22 @@ import {
|
||||||
Expression,
|
Expression,
|
||||||
LetDeclaration,
|
LetDeclaration,
|
||||||
Pattern,
|
Pattern,
|
||||||
ReferenceExpression,
|
|
||||||
SourceFile,
|
SourceFile,
|
||||||
Syntax,
|
Syntax,
|
||||||
SyntaxKind,
|
SyntaxKind,
|
||||||
TypeExpression
|
TypeExpression
|
||||||
} from "./cst";
|
} from "./cst";
|
||||||
import { ArityMismatchDiagnostic, BindingNotFoudDiagnostic, describeType, Diagnostics, UnificationFailedDiagnostic } from "./diagnostics";
|
import { ArityMismatchDiagnostic, BindingNotFoudDiagnostic, describeType, Diagnostics, UnificationFailedDiagnostic } from "./diagnostics";
|
||||||
import { assert } from "./util";
|
import { assert, isEmpty } from "./util";
|
||||||
import { DirectedHashGraph, Graph, strongconnect } from "yagl"
|
import { LabeledDirectedHashGraph, LabeledGraph, strongconnect } from "yagl"
|
||||||
|
|
||||||
|
// FIXME Duplicate definitions are not checked
|
||||||
|
|
||||||
|
const MAX_TYPE_ERROR_COUNT = 5;
|
||||||
|
|
||||||
|
type NodeWithBindings = SourceFile | LetDeclaration;
|
||||||
|
|
||||||
|
type ReferenceGraph = LabeledGraph<NodeWithBindings, boolean>;
|
||||||
|
|
||||||
export enum TypeKind {
|
export enum TypeKind {
|
||||||
Arrow,
|
Arrow,
|
||||||
|
@ -386,7 +393,6 @@ export class Checker {
|
||||||
private boolType = new TCon(this.nextConTypeId++, [], 'Bool');
|
private boolType = new TCon(this.nextConTypeId++, [], 'Bool');
|
||||||
|
|
||||||
private contexts: InferContext[] = [];
|
private contexts: InferContext[] = [];
|
||||||
private constraints: Constraint[] = [];
|
|
||||||
|
|
||||||
private solution = new TVSub();
|
private solution = new TVSub();
|
||||||
|
|
||||||
|
@ -416,11 +422,8 @@ export class Checker {
|
||||||
}
|
}
|
||||||
|
|
||||||
private addConstraint(constraint: Constraint): void {
|
private addConstraint(constraint: Constraint): void {
|
||||||
this.constraints.push(constraint);
|
|
||||||
if (this.contexts.length > 0) {
|
|
||||||
this.contexts[this.contexts.length-1].constraints.push(constraint);
|
this.contexts[this.contexts.length-1].constraints.push(constraint);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private pushContext(context: InferContext) {
|
private pushContext(context: InferContext) {
|
||||||
this.contexts.push(context);
|
this.contexts.push(context);
|
||||||
|
@ -461,31 +464,6 @@ export class Checker {
|
||||||
context.env.add(name, scheme);
|
context.env.add(name, scheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
private forwardDeclare(node: Syntax): void {
|
|
||||||
|
|
||||||
switch (node.kind) {
|
|
||||||
|
|
||||||
case SyntaxKind.SourceFile:
|
|
||||||
{
|
|
||||||
for (const element of node.elements) {
|
|
||||||
this.forwardDeclare(element);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case SyntaxKind.ExpressionStatement:
|
|
||||||
case SyntaxKind.ReturnStatement:
|
|
||||||
{
|
|
||||||
// TODO This should be updated if block-scoped expressions are allowed.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case SyntaxKind.LetDeclaration:
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public infer(node: Syntax): void {
|
public infer(node: Syntax): void {
|
||||||
|
|
||||||
switch (node.kind) {
|
switch (node.kind) {
|
||||||
|
@ -685,7 +663,7 @@ export class Checker {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private addReferences(graph: Graph<LetDeclaration>, node: Syntax, source: LetDeclaration | null) {
|
private addReferencesToGraph(graph: ReferenceGraph, node: Syntax, source: LetDeclaration | SourceFile) {
|
||||||
|
|
||||||
switch (node.kind) {
|
switch (node.kind) {
|
||||||
|
|
||||||
|
@ -695,7 +673,7 @@ export class Checker {
|
||||||
case SyntaxKind.SourceFile:
|
case SyntaxKind.SourceFile:
|
||||||
{
|
{
|
||||||
for (const element of node.elements) {
|
for (const element of node.elements) {
|
||||||
this.addReferences(graph, element, source);
|
this.addReferencesToGraph(graph, element, source);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -704,38 +682,40 @@ export class Checker {
|
||||||
{
|
{
|
||||||
assert(node.name.modulePath.length === 0);
|
assert(node.name.modulePath.length === 0);
|
||||||
const target = node.getScope().lookup(node.name.name.text);
|
const target = node.getScope().lookup(node.name.name.text);
|
||||||
if (source !== null && target !== null && target.kind === SyntaxKind.LetDeclaration) {
|
if (target === null || target.kind === SyntaxKind.Param) {
|
||||||
graph.addEdge(source, target);
|
break;
|
||||||
}
|
}
|
||||||
|
assert(target.kind === SyntaxKind.LetDeclaration || target.kind === SyntaxKind.SourceFile);
|
||||||
|
graph.addEdge(source, target, true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SyntaxKind.NamedTupleExpression:
|
case SyntaxKind.NamedTupleExpression:
|
||||||
{
|
{
|
||||||
for (const arg of node.elements) {
|
for (const arg of node.elements) {
|
||||||
this.addReferences(graph, arg, source);
|
this.addReferencesToGraph(graph, arg, source);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SyntaxKind.NestedExpression:
|
case SyntaxKind.NestedExpression:
|
||||||
{
|
{
|
||||||
this.addReferences(graph, node.expression, source);
|
this.addReferencesToGraph(graph, node.expression, source);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SyntaxKind.InfixExpression:
|
case SyntaxKind.InfixExpression:
|
||||||
{
|
{
|
||||||
this.addReferences(graph, node.left, source);
|
this.addReferencesToGraph(graph, node.left, source);
|
||||||
this.addReferences(graph, node.right, source);
|
this.addReferencesToGraph(graph, node.right, source);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SyntaxKind.CallExpression:
|
case SyntaxKind.CallExpression:
|
||||||
{
|
{
|
||||||
this.addReferences(graph, node.func, source);
|
this.addReferencesToGraph(graph, node.func, source);
|
||||||
for (const arg of node.args) {
|
for (const arg of node.args) {
|
||||||
this.addReferences(graph, arg, source);
|
this.addReferencesToGraph(graph, arg, source);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -744,10 +724,10 @@ export class Checker {
|
||||||
{
|
{
|
||||||
for (const cs of node.cases) {
|
for (const cs of node.cases) {
|
||||||
if (cs.test !== null) {
|
if (cs.test !== null) {
|
||||||
this.addReferences(graph, cs.test, source);
|
this.addReferencesToGraph(graph, cs.test, source);
|
||||||
}
|
}
|
||||||
for (const element of cs.elements) {
|
for (const element of cs.elements) {
|
||||||
this.addReferences(graph, element, source);
|
this.addReferencesToGraph(graph, element, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -755,13 +735,13 @@ export class Checker {
|
||||||
|
|
||||||
case SyntaxKind.ExpressionStatement:
|
case SyntaxKind.ExpressionStatement:
|
||||||
{
|
{
|
||||||
this.addReferences(graph, node.expression, source);
|
this.addReferencesToGraph(graph, node.expression, source);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SyntaxKind.ReturnStatement:
|
case SyntaxKind.ReturnStatement:
|
||||||
{
|
{
|
||||||
if (node.expression !== null) {
|
if (node.expression !== null) {
|
||||||
this.addReferences(graph, node.expression, source);
|
this.addReferencesToGraph(graph, node.expression, source);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -772,13 +752,13 @@ export class Checker {
|
||||||
switch (node.body.kind) {
|
switch (node.body.kind) {
|
||||||
case SyntaxKind.ExprBody:
|
case SyntaxKind.ExprBody:
|
||||||
{
|
{
|
||||||
this.addReferences(graph, node.body.expression, node);
|
this.addReferencesToGraph(graph, node.body.expression, node);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SyntaxKind.BlockBody:
|
case SyntaxKind.BlockBody:
|
||||||
{
|
{
|
||||||
for (const element of node.body.elements) {
|
for (const element of node.body.elements) {
|
||||||
this.addReferences(graph, element, node);
|
this.addReferencesToGraph(graph, element, node);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -794,6 +774,44 @@ export class Checker {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private completeReferenceGraph(graph: ReferenceGraph, node: Syntax): void {
|
||||||
|
|
||||||
|
switch (node.kind) {
|
||||||
|
|
||||||
|
case SyntaxKind.SourceFile:
|
||||||
|
{
|
||||||
|
for (const element of node.elements) {
|
||||||
|
this.completeReferenceGraph(graph, element);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SyntaxKind.LetDeclaration:
|
||||||
|
{
|
||||||
|
if (isEmpty(graph.getSourceVertices(node))) {
|
||||||
|
const source = node.parent!.getScope().node;
|
||||||
|
assert(source.kind === SyntaxKind.LetDeclaration || source.kind === SyntaxKind.SourceFile);
|
||||||
|
graph.addEdge(source, node, false);
|
||||||
|
}
|
||||||
|
if (node.body !== null && node.body.kind === SyntaxKind.BlockBody) {
|
||||||
|
for (const element of node.body.elements) {
|
||||||
|
this.completeReferenceGraph(graph, element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SyntaxKind.ReturnStatement:
|
||||||
|
case SyntaxKind.ExpressionStatement:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error(`Unexpected ${node}`);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private initialize(node: Syntax, parentEnv: TypeEnv | null): void {
|
private initialize(node: Syntax, parentEnv: TypeEnv | null): void {
|
||||||
|
|
||||||
switch (node.kind) {
|
switch (node.kind) {
|
||||||
|
@ -851,8 +869,9 @@ export class Checker {
|
||||||
env.add('==', new Forall([ a ], [], new TArrow([ a, a ], this.boolType)));
|
env.add('==', new Forall([ a ], [], new TArrow([ a, a ], this.boolType)));
|
||||||
env.add('not', new Forall([], [], new TArrow([ this.boolType ], this.boolType)));
|
env.add('not', new Forall([], [], new TArrow([ this.boolType ], this.boolType)));
|
||||||
|
|
||||||
const graph = new DirectedHashGraph<LetDeclaration>();
|
const graph = new LabeledDirectedHashGraph<NodeWithBindings, boolean>();
|
||||||
this.addReferences(graph, node, null);
|
this.addReferencesToGraph(graph, node, node);
|
||||||
|
this.completeReferenceGraph(graph, node);
|
||||||
|
|
||||||
this.initialize(node, env);
|
this.initialize(node, env);
|
||||||
|
|
||||||
|
@ -860,11 +879,18 @@ export class Checker {
|
||||||
|
|
||||||
for (const nodes of sccs) {
|
for (const nodes of sccs) {
|
||||||
|
|
||||||
|
if (nodes.some(n => n.kind === SyntaxKind.SourceFile)) {
|
||||||
|
assert(nodes.length === 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const typeVars = new TVSet();
|
const typeVars = new TVSet();
|
||||||
const constraints = new ConstraintSet();
|
const constraints = new ConstraintSet();
|
||||||
|
|
||||||
for (const node of nodes) {
|
for (const node of nodes) {
|
||||||
|
|
||||||
|
assert(node.kind === SyntaxKind.LetDeclaration);
|
||||||
|
|
||||||
const env = node.typeEnv!;
|
const env = node.typeEnv!;
|
||||||
const context: InferContext = {
|
const context: InferContext = {
|
||||||
typeVars,
|
typeVars,
|
||||||
|
@ -907,12 +933,20 @@ export class Checker {
|
||||||
|
|
||||||
for (const nodes of sccs) {
|
for (const nodes of sccs) {
|
||||||
|
|
||||||
|
if (nodes.some(n => n.kind === SyntaxKind.SourceFile)) {
|
||||||
|
assert(nodes.length === 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
for (const node of nodes) {
|
for (const node of nodes) {
|
||||||
|
assert(node.kind === SyntaxKind.LetDeclaration);
|
||||||
node.active = true;
|
node.active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const node of nodes) {
|
for (const node of nodes) {
|
||||||
|
|
||||||
|
assert(node.kind === SyntaxKind.LetDeclaration);
|
||||||
|
|
||||||
const context = node.context!;
|
const context = node.context!;
|
||||||
const returnType = context.returnType!;
|
const returnType = context.returnType!;
|
||||||
this.contexts.push(context);
|
this.contexts.push(context);
|
||||||
|
@ -933,7 +967,13 @@ export class Checker {
|
||||||
case SyntaxKind.BlockBody:
|
case SyntaxKind.BlockBody:
|
||||||
{
|
{
|
||||||
for (const element of node.body.elements) {
|
for (const element of node.body.elements) {
|
||||||
if (element.kind !== SyntaxKind.LetDeclaration) {
|
if (element.kind === SyntaxKind.LetDeclaration
|
||||||
|
&& element.pattern.kind === SyntaxKind.BindPattern
|
||||||
|
&& graph.hasEdge(node, element, false)) {
|
||||||
|
const scheme = this.lookup(element.pattern.name.text);
|
||||||
|
assert(scheme !== null);
|
||||||
|
this.instantiate(scheme, null);
|
||||||
|
} else {
|
||||||
this.infer(element);
|
this.infer(element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -946,26 +986,35 @@ export class Checker {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const node of nodes) {
|
for (const node of nodes) {
|
||||||
|
assert(node.kind === SyntaxKind.LetDeclaration);
|
||||||
node.active = false;
|
node.active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const element of node.elements) {
|
for (const element of node.elements) {
|
||||||
if (element.kind !== SyntaxKind.LetDeclaration) {
|
if (element.kind === SyntaxKind.LetDeclaration
|
||||||
|
&& element.pattern.kind === SyntaxKind.BindPattern
|
||||||
|
&& graph.hasEdge(node, element, false)) {
|
||||||
|
const scheme = this.lookup(element.pattern.name.text);
|
||||||
|
assert(scheme !== null);
|
||||||
|
this.instantiate(scheme, null);
|
||||||
|
} else {
|
||||||
this.infer(element);
|
this.infer(element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.popContext(context);
|
this.popContext(context);
|
||||||
|
|
||||||
this.solve(new CMany(this.constraints), this.solution);
|
this.solve(new CMany(constraints), this.solution);
|
||||||
}
|
}
|
||||||
|
|
||||||
private solve(constraint: Constraint, solution: TVSub): void {
|
private solve(constraint: Constraint, solution: TVSub): void {
|
||||||
|
|
||||||
const queue = [ constraint ];
|
const queue = [ constraint ];
|
||||||
|
|
||||||
|
let errorCount = 0;
|
||||||
|
|
||||||
while (queue.length > 0) {
|
while (queue.length > 0) {
|
||||||
|
|
||||||
const constraint = queue.pop()!;
|
const constraint = queue.pop()!;
|
||||||
|
@ -982,8 +1031,12 @@ export class Checker {
|
||||||
|
|
||||||
case ConstraintKind.Equal:
|
case ConstraintKind.Equal:
|
||||||
{
|
{
|
||||||
|
//constraint.dump();
|
||||||
if (!this.unify(constraint.left, constraint.right, solution, constraint)) {
|
if (!this.unify(constraint.left, constraint.right, solution, constraint)) {
|
||||||
// TODO break or continue?
|
errorCount++;
|
||||||
|
if (errorCount === MAX_TYPE_ERROR_COUNT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,13 @@ export function countDigits(x: number, base: number = 10) {
|
||||||
return x === 0 ? 1 : Math.ceil(Math.log(x+1) / Math.log(base))
|
return x === 0 ? 1 : Math.ceil(Math.log(x+1) / Math.log(base))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isEmpty<T>(iter: Iterable<T> | Iterator<T>): boolean {
|
||||||
|
if ((iter as any)[Symbol.iterator] !== undefined) {
|
||||||
|
iter = (iter as any)[Symbol.iterator]();
|
||||||
|
}
|
||||||
|
return !!(iter as Iterator<T>).next().done;
|
||||||
|
}
|
||||||
|
|
||||||
export type JSONValue = null | boolean | number | string | JSONArray | JSONObject
|
export type JSONValue = null | boolean | number | string | JSONArray | JSONObject
|
||||||
export type JSONArray = Array<JSONValue>;
|
export type JSONArray = Array<JSONValue>;
|
||||||
export type JSONObject = { [key: string]: JSONValue };
|
export type JSONObject = { [key: string]: JSONValue };
|
||||||
|
|
Loading…
Reference in a new issue