Re-write the type checker to be more robust
This commit is contained in:
parent
9ef9ef82d6
commit
def4adba40
8 changed files with 483 additions and 215 deletions
21
spec/ast.txt
21
spec/ast.txt
|
@ -36,16 +36,17 @@ node BoltAssignment > BoltToken {
|
||||||
operator: Option<String>,
|
operator: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
node BoltComma > BoltToken;
|
node BoltComma > BoltToken;
|
||||||
node BoltSemi > BoltToken;
|
node BoltSemi > BoltToken;
|
||||||
node BoltColon > BoltToken;
|
node BoltColon > BoltToken;
|
||||||
node BoltDot > BoltToken;
|
node BoltDot > BoltToken;
|
||||||
node BoltDotDot > BoltToken;
|
node BoltDotDot > BoltToken;
|
||||||
node BoltRArrow > BoltToken;
|
node BoltRArrow > BoltToken;
|
||||||
node BoltLArrow > BoltToken;
|
node BoltRArrowAlt > BoltToken;
|
||||||
node BoltEqSign > BoltToken;
|
node BoltLArrow > BoltToken;
|
||||||
node BoltGtSign > BoltToken;
|
node BoltEqSign > BoltToken;
|
||||||
node BoltLtSign > BoltToken;
|
node BoltGtSign > BoltToken;
|
||||||
|
node BoltLtSign > BoltToken;
|
||||||
|
|
||||||
node BoltKeyword;
|
node BoltKeyword;
|
||||||
|
|
||||||
|
|
252
src/ast.d.ts
vendored
252
src/ast.d.ts
vendored
|
@ -13,127 +13,128 @@ export const enum SyntaxKind {
|
||||||
BoltDot = 15,
|
BoltDot = 15,
|
||||||
BoltDotDot = 16,
|
BoltDotDot = 16,
|
||||||
BoltRArrow = 17,
|
BoltRArrow = 17,
|
||||||
BoltLArrow = 18,
|
BoltRArrowAlt = 18,
|
||||||
BoltEqSign = 19,
|
BoltLArrow = 19,
|
||||||
BoltGtSign = 20,
|
BoltEqSign = 20,
|
||||||
BoltLtSign = 21,
|
BoltGtSign = 21,
|
||||||
BoltFnKeyword = 23,
|
BoltLtSign = 22,
|
||||||
BoltForeignKeyword = 24,
|
BoltFnKeyword = 24,
|
||||||
BoltForKeyword = 25,
|
BoltForeignKeyword = 25,
|
||||||
BoltLetKeyword = 26,
|
BoltForKeyword = 26,
|
||||||
BoltReturnKeyword = 27,
|
BoltLetKeyword = 27,
|
||||||
BoltLoopKeyword = 28,
|
BoltReturnKeyword = 28,
|
||||||
BoltYieldKeyword = 29,
|
BoltLoopKeyword = 29,
|
||||||
BoltMatchKeyword = 30,
|
BoltYieldKeyword = 30,
|
||||||
BoltImportKeyword = 31,
|
BoltMatchKeyword = 31,
|
||||||
BoltPubKeyword = 32,
|
BoltImportKeyword = 32,
|
||||||
BoltModKeyword = 33,
|
BoltPubKeyword = 33,
|
||||||
BoltMutKeyword = 34,
|
BoltModKeyword = 34,
|
||||||
BoltEnumKeyword = 35,
|
BoltMutKeyword = 35,
|
||||||
BoltStructKeyword = 36,
|
BoltEnumKeyword = 36,
|
||||||
BoltTypeKeyword = 37,
|
BoltStructKeyword = 37,
|
||||||
BoltTraitKeyword = 38,
|
BoltTypeKeyword = 38,
|
||||||
BoltImplKeyword = 39,
|
BoltTraitKeyword = 39,
|
||||||
BoltParenthesized = 41,
|
BoltImplKeyword = 40,
|
||||||
BoltBraced = 42,
|
BoltParenthesized = 42,
|
||||||
BoltBracketed = 43,
|
BoltBraced = 43,
|
||||||
BoltSourceFile = 44,
|
BoltBracketed = 44,
|
||||||
BoltQualName = 45,
|
BoltSourceFile = 45,
|
||||||
BoltReferenceTypeExpression = 47,
|
BoltQualName = 46,
|
||||||
BoltTypeParameter = 48,
|
BoltReferenceTypeExpression = 48,
|
||||||
BoltBindPattern = 50,
|
BoltTypeParameter = 49,
|
||||||
BoltTypePattern = 51,
|
BoltBindPattern = 51,
|
||||||
BoltExpressionPattern = 52,
|
BoltTypePattern = 52,
|
||||||
BoltTuplePatternElement = 53,
|
BoltExpressionPattern = 53,
|
||||||
BoltTuplePattern = 54,
|
BoltTuplePatternElement = 54,
|
||||||
BoltRecordPatternField = 55,
|
BoltTuplePattern = 55,
|
||||||
BoltRecordPattern = 56,
|
BoltRecordPatternField = 56,
|
||||||
BoltReferenceExpression = 58,
|
BoltRecordPattern = 57,
|
||||||
BoltCallExpression = 59,
|
BoltReferenceExpression = 59,
|
||||||
BoltYieldExpression = 60,
|
BoltCallExpression = 60,
|
||||||
BoltMatchArm = 61,
|
BoltYieldExpression = 61,
|
||||||
BoltMatchExpression = 62,
|
BoltMatchArm = 62,
|
||||||
BoltCase = 63,
|
BoltMatchExpression = 63,
|
||||||
BoltCaseExpression = 64,
|
BoltCase = 64,
|
||||||
BoltBlockExpression = 65,
|
BoltCaseExpression = 65,
|
||||||
BoltConstantExpression = 66,
|
BoltBlockExpression = 66,
|
||||||
BoltReturnStatement = 68,
|
BoltConstantExpression = 67,
|
||||||
BoltResumeStatement = 69,
|
BoltReturnStatement = 69,
|
||||||
BoltExpressionStatement = 70,
|
BoltResumeStatement = 70,
|
||||||
BoltParameter = 71,
|
BoltExpressionStatement = 71,
|
||||||
BoltModule = 75,
|
BoltParameter = 72,
|
||||||
BoltFunctionDeclaration = 77,
|
BoltModule = 76,
|
||||||
BoltVariableDeclaration = 78,
|
BoltFunctionDeclaration = 78,
|
||||||
BoltPlainImportSymbol = 80,
|
BoltVariableDeclaration = 79,
|
||||||
BoltImportDeclaration = 81,
|
BoltPlainImportSymbol = 81,
|
||||||
BoltTraitDeclaration = 82,
|
BoltImportDeclaration = 82,
|
||||||
BoltImplDeclaration = 83,
|
BoltTraitDeclaration = 83,
|
||||||
BoltTypeAliasDeclaration = 84,
|
BoltImplDeclaration = 84,
|
||||||
BoltRecordField = 86,
|
BoltTypeAliasDeclaration = 85,
|
||||||
BoltRecordDeclaration = 87,
|
BoltRecordField = 87,
|
||||||
BoltMacroCall = 89,
|
BoltRecordDeclaration = 88,
|
||||||
JSOperator = 92,
|
BoltMacroCall = 90,
|
||||||
JSIdentifier = 93,
|
JSOperator = 93,
|
||||||
JSString = 94,
|
JSIdentifier = 94,
|
||||||
JSInteger = 95,
|
JSString = 95,
|
||||||
JSFromKeyword = 96,
|
JSInteger = 96,
|
||||||
JSReturnKeyword = 97,
|
JSFromKeyword = 97,
|
||||||
JSTryKeyword = 98,
|
JSReturnKeyword = 98,
|
||||||
JSFinallyKeyword = 99,
|
JSTryKeyword = 99,
|
||||||
JSCatchKeyword = 100,
|
JSFinallyKeyword = 100,
|
||||||
JSImportKeyword = 101,
|
JSCatchKeyword = 101,
|
||||||
JSAsKeyword = 102,
|
JSImportKeyword = 102,
|
||||||
JSConstKeyword = 103,
|
JSAsKeyword = 103,
|
||||||
JSLetKeyword = 104,
|
JSConstKeyword = 104,
|
||||||
JSExportKeyword = 105,
|
JSLetKeyword = 105,
|
||||||
JSFunctionKeyword = 106,
|
JSExportKeyword = 106,
|
||||||
JSWhileKeyword = 107,
|
JSFunctionKeyword = 107,
|
||||||
JSForKeyword = 108,
|
JSWhileKeyword = 108,
|
||||||
JSCloseBrace = 109,
|
JSForKeyword = 109,
|
||||||
JSCloseBracket = 110,
|
JSCloseBrace = 110,
|
||||||
JSCloseParen = 111,
|
JSCloseBracket = 111,
|
||||||
JSOpenBrace = 112,
|
JSCloseParen = 112,
|
||||||
JSOpenBracket = 113,
|
JSOpenBrace = 113,
|
||||||
JSOpenParen = 114,
|
JSOpenBracket = 114,
|
||||||
JSSemi = 115,
|
JSOpenParen = 115,
|
||||||
JSComma = 116,
|
JSSemi = 116,
|
||||||
JSDot = 117,
|
JSComma = 117,
|
||||||
JSDotDotDot = 118,
|
JSDot = 118,
|
||||||
JSMulOp = 119,
|
JSDotDotDot = 119,
|
||||||
JSAddOp = 120,
|
JSMulOp = 120,
|
||||||
JSDivOp = 121,
|
JSAddOp = 121,
|
||||||
JSSubOp = 122,
|
JSDivOp = 122,
|
||||||
JSLtOp = 123,
|
JSSubOp = 123,
|
||||||
JSGtOp = 124,
|
JSLtOp = 124,
|
||||||
JSBOrOp = 125,
|
JSGtOp = 125,
|
||||||
JSBXorOp = 126,
|
JSBOrOp = 126,
|
||||||
JSBAndOp = 127,
|
JSBXorOp = 127,
|
||||||
JSBNotOp = 128,
|
JSBAndOp = 128,
|
||||||
JSNotOp = 129,
|
JSBNotOp = 129,
|
||||||
JSBindPattern = 131,
|
JSNotOp = 130,
|
||||||
JSConstantExpression = 133,
|
JSBindPattern = 132,
|
||||||
JSMemberExpression = 134,
|
JSConstantExpression = 134,
|
||||||
JSCallExpression = 135,
|
JSMemberExpression = 135,
|
||||||
JSBinaryExpression = 136,
|
JSCallExpression = 136,
|
||||||
JSUnaryExpression = 137,
|
JSBinaryExpression = 137,
|
||||||
JSNewExpression = 138,
|
JSUnaryExpression = 138,
|
||||||
JSSequenceExpression = 139,
|
JSNewExpression = 139,
|
||||||
JSConditionalExpression = 140,
|
JSSequenceExpression = 140,
|
||||||
JSLiteralExpression = 142,
|
JSConditionalExpression = 141,
|
||||||
JSReferenceExpression = 143,
|
JSLiteralExpression = 143,
|
||||||
JSCatchBlock = 146,
|
JSReferenceExpression = 144,
|
||||||
JSTryCatchStatement = 147,
|
JSCatchBlock = 147,
|
||||||
JSExpressionStatement = 148,
|
JSTryCatchStatement = 148,
|
||||||
JSConditionalStatement = 149,
|
JSExpressionStatement = 149,
|
||||||
JSReturnStatement = 150,
|
JSConditionalStatement = 150,
|
||||||
JSParameter = 151,
|
JSReturnStatement = 151,
|
||||||
JSImportStarBinding = 155,
|
JSParameter = 152,
|
||||||
JSImportAsBinding = 156,
|
JSImportStarBinding = 156,
|
||||||
JSImportDeclaration = 157,
|
JSImportAsBinding = 157,
|
||||||
JSFunctionDeclaration = 158,
|
JSImportDeclaration = 158,
|
||||||
JSArrowFunctionDeclaration = 159,
|
JSFunctionDeclaration = 159,
|
||||||
JSLetDeclaration = 160,
|
JSArrowFunctionDeclaration = 160,
|
||||||
JSSourceFile = 161,
|
JSLetDeclaration = 161,
|
||||||
|
JSSourceFile = 162,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -175,6 +176,7 @@ export type BoltToken
|
||||||
| BoltDot
|
| BoltDot
|
||||||
| BoltDotDot
|
| BoltDotDot
|
||||||
| BoltRArrow
|
| BoltRArrow
|
||||||
|
| BoltRArrowAlt
|
||||||
| BoltLArrow
|
| BoltLArrow
|
||||||
| BoltEqSign
|
| BoltEqSign
|
||||||
| BoltGtSign
|
| BoltGtSign
|
||||||
|
@ -255,6 +257,10 @@ export interface BoltRArrow extends SyntaxBase<SyntaxKind.BoltRArrow> {
|
||||||
kind: SyntaxKind.BoltRArrow;
|
kind: SyntaxKind.BoltRArrow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface BoltRArrowAlt extends SyntaxBase<SyntaxKind.BoltRArrowAlt> {
|
||||||
|
kind: SyntaxKind.BoltRArrowAlt;
|
||||||
|
}
|
||||||
|
|
||||||
export interface BoltLArrow extends SyntaxBase<SyntaxKind.BoltLArrow> {
|
export interface BoltLArrow extends SyntaxBase<SyntaxKind.BoltLArrow> {
|
||||||
kind: SyntaxKind.BoltLArrow;
|
kind: SyntaxKind.BoltLArrow;
|
||||||
}
|
}
|
||||||
|
@ -1085,6 +1091,7 @@ export type BoltSyntax
|
||||||
| BoltDot
|
| BoltDot
|
||||||
| BoltDotDot
|
| BoltDotDot
|
||||||
| BoltRArrow
|
| BoltRArrow
|
||||||
|
| BoltRArrowAlt
|
||||||
| BoltLArrow
|
| BoltLArrow
|
||||||
| BoltEqSign
|
| BoltEqSign
|
||||||
| BoltGtSign
|
| BoltGtSign
|
||||||
|
@ -1225,6 +1232,7 @@ export type Syntax
|
||||||
| BoltDot
|
| BoltDot
|
||||||
| BoltDotDot
|
| BoltDotDot
|
||||||
| BoltRArrow
|
| BoltRArrow
|
||||||
|
| BoltRArrowAlt
|
||||||
| BoltLArrow
|
| BoltLArrow
|
||||||
| BoltEqSign
|
| BoltEqSign
|
||||||
| BoltGtSign
|
| BoltGtSign
|
||||||
|
@ -1363,6 +1371,7 @@ export function createBoltColon(span?: TextSpan | null): BoltColon;
|
||||||
export function createBoltDot(span?: TextSpan | null): BoltDot;
|
export function createBoltDot(span?: TextSpan | null): BoltDot;
|
||||||
export function createBoltDotDot(span?: TextSpan | null): BoltDotDot;
|
export function createBoltDotDot(span?: TextSpan | null): BoltDotDot;
|
||||||
export function createBoltRArrow(span?: TextSpan | null): BoltRArrow;
|
export function createBoltRArrow(span?: TextSpan | null): BoltRArrow;
|
||||||
|
export function createBoltRArrowAlt(span?: TextSpan | null): BoltRArrowAlt;
|
||||||
export function createBoltLArrow(span?: TextSpan | null): BoltLArrow;
|
export function createBoltLArrow(span?: TextSpan | null): BoltLArrow;
|
||||||
export function createBoltEqSign(span?: TextSpan | null): BoltEqSign;
|
export function createBoltEqSign(span?: TextSpan | null): BoltEqSign;
|
||||||
export function createBoltGtSign(span?: TextSpan | null): BoltGtSign;
|
export function createBoltGtSign(span?: TextSpan | null): BoltGtSign;
|
||||||
|
@ -1500,6 +1509,7 @@ export function isBoltColon(value: any): value is BoltColon;
|
||||||
export function isBoltDot(value: any): value is BoltDot;
|
export function isBoltDot(value: any): value is BoltDot;
|
||||||
export function isBoltDotDot(value: any): value is BoltDotDot;
|
export function isBoltDotDot(value: any): value is BoltDotDot;
|
||||||
export function isBoltRArrow(value: any): value is BoltRArrow;
|
export function isBoltRArrow(value: any): value is BoltRArrow;
|
||||||
|
export function isBoltRArrowAlt(value: any): value is BoltRArrowAlt;
|
||||||
export function isBoltLArrow(value: any): value is BoltLArrow;
|
export function isBoltLArrow(value: any): value is BoltLArrow;
|
||||||
export function isBoltEqSign(value: any): value is BoltEqSign;
|
export function isBoltEqSign(value: any): value is BoltEqSign;
|
||||||
export function isBoltGtSign(value: any): value is BoltGtSign;
|
export function isBoltGtSign(value: any): value is BoltGtSign;
|
||||||
|
|
299
src/checker.ts
299
src/checker.ts
|
@ -23,7 +23,25 @@
|
||||||
* Note that the `pub`-keyword is not present on `MyType1`.
|
* Note that the `pub`-keyword is not present on `MyType1`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Syntax, SyntaxKind, BoltReferenceExpression, BoltDeclaration, BoltSourceFile, BoltSyntax, BoltReferenceTypeExpression, BoltTypeDeclaration, BoltExpression, BoltFunctionDeclaration, BoltFunctionBodyElement, kindToString, createBoltReferenceTypeExpression, createBoltIdentifier} from "./ast";
|
import {
|
||||||
|
Syntax,
|
||||||
|
SyntaxKind,
|
||||||
|
BoltReferenceExpression,
|
||||||
|
BoltDeclaration,
|
||||||
|
BoltSourceFile,
|
||||||
|
BoltSyntax,
|
||||||
|
BoltReferenceTypeExpression,
|
||||||
|
BoltTypeDeclaration,
|
||||||
|
BoltExpression,
|
||||||
|
BoltFunctionDeclaration,
|
||||||
|
BoltFunctionBodyElement,
|
||||||
|
kindToString,
|
||||||
|
BoltStatement,
|
||||||
|
BoltTypeExpression,
|
||||||
|
BoltSourceElement,
|
||||||
|
isBoltStatement,
|
||||||
|
isBoltDeclaration
|
||||||
|
} from "./ast";
|
||||||
import {FastStringMap, memoize, assert} from "./util";
|
import {FastStringMap, memoize, assert} from "./util";
|
||||||
import {
|
import {
|
||||||
DiagnosticPrinter,
|
DiagnosticPrinter,
|
||||||
|
@ -34,7 +52,8 @@ import {
|
||||||
E_DECLARATION_NOT_FOUND,
|
E_DECLARATION_NOT_FOUND,
|
||||||
E_INVALID_ARGUMENTS
|
E_INVALID_ARGUMENTS
|
||||||
} from "./diagnostics";
|
} from "./diagnostics";
|
||||||
import {createAnyType, isOpaqueType, createOpaqueType, Type} from "./types";
|
import { createAnyType, isOpaqueType, createOpaqueType, Type, createVoidType, createVariantType, isVoidType } from "./types";
|
||||||
|
import { getReturnStatementsInFunctionBody } from "./common";
|
||||||
|
|
||||||
interface SymbolInfo {
|
interface SymbolInfo {
|
||||||
declarations: BoltDeclaration[];
|
declarations: BoltDeclaration[];
|
||||||
|
@ -78,74 +97,223 @@ export class TypeChecker {
|
||||||
|
|
||||||
public checkSourceFile(node: BoltSourceFile): void {
|
public checkSourceFile(node: BoltSourceFile): void {
|
||||||
|
|
||||||
const refExps = node.findAllChildrenOfKind(SyntaxKind.BoltReferenceExpression);
|
const self = this;
|
||||||
for (const refExp of refExps) {
|
for (const element of node.elements) {
|
||||||
if (this.resolveReferenceExpression(refExp) === null) {
|
visitSourceElement(element);
|
||||||
this.diagnostics.add({
|
|
||||||
message: E_DECLARATION_NOT_FOUND,
|
|
||||||
args: { name: refExp.name.name.text },
|
|
||||||
severity: 'error',
|
|
||||||
node: refExp,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const typeRefExps = node.findAllChildrenOfKind(SyntaxKind.BoltReferenceTypeExpression);
|
function visitExpression(node: BoltExpression) {
|
||||||
for (const typeRefExp of typeRefExps) {
|
|
||||||
if (this.resolveTypeReferenceExpression(typeRefExp) === null) {
|
|
||||||
this.diagnostics.add({
|
|
||||||
message: E_TYPE_DECLARATION_NOT_FOUND,
|
|
||||||
args: { name: typeRefExp.name.name.text },
|
|
||||||
severity: 'error',
|
|
||||||
node: typeRefExp,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const callExps = node.findAllChildrenOfKind(SyntaxKind.BoltCallExpression);
|
switch (node.kind) {
|
||||||
|
|
||||||
for (const callExp of callExps) {
|
case SyntaxKind.BoltReferenceExpression:
|
||||||
|
{
|
||||||
const fnDecls = this.getAllFunctionsInExpression(callExp.operator);
|
if (self.resolveReferenceExpression(node) === null) {
|
||||||
|
self.diagnostics.add({
|
||||||
for (const fnDecl of fnDecls) {
|
message: E_DECLARATION_NOT_FOUND,
|
||||||
|
args: { name: node.name.name.text },
|
||||||
if (fnDecl.params.length > callExp.operands.length) {
|
|
||||||
this.diagnostics.add({
|
|
||||||
message: E_TOO_FEW_ARGUMENTS_FOR_FUNCTION_CALL,
|
|
||||||
args: { expected: fnDecl.params.length, actual: callExp.operands.length },
|
|
||||||
severity: 'error',
|
|
||||||
node: callExp,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fnDecl.params.length < callExp.operands.length) {
|
|
||||||
this.diagnostics.add({
|
|
||||||
message: E_TOO_MANY_ARGUMENTS_FOR_FUNCTION_CALL,
|
|
||||||
args: { expected: fnDecl.params.length, actual: callExp.operands.length },
|
|
||||||
severity: 'error',
|
|
||||||
node: callExp,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const paramCount = fnDecl.params.length;
|
|
||||||
for (let i = 0; i < paramCount; i++) {
|
|
||||||
const arg = callExp.operands[i];
|
|
||||||
const param = fnDecl.params[i];
|
|
||||||
let argType = this.getTypeOfNode(arg);
|
|
||||||
let paramType = this.getTypeOfNode(param);
|
|
||||||
if (!this.isTypeAssignableTo(argType, paramType)) {
|
|
||||||
this.diagnostics.add({
|
|
||||||
message: E_INVALID_ARGUMENTS,
|
|
||||||
severity: 'error',
|
severity: 'error',
|
||||||
args: { name: fnDecl.name.text },
|
node: node,
|
||||||
node: arg,
|
})
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SyntaxKind.BoltCallExpression:
|
||||||
|
{
|
||||||
|
|
||||||
|
const fnDecls = self.getAllFunctionsInExpression(node.operator);
|
||||||
|
|
||||||
|
for (const fnDecl of fnDecls) {
|
||||||
|
|
||||||
|
if (fnDecl.params.length > node.operands.length) {
|
||||||
|
|
||||||
|
self.diagnostics.add({
|
||||||
|
message: E_TOO_FEW_ARGUMENTS_FOR_FUNCTION_CALL,
|
||||||
|
args: { expected: fnDecl.params.length, actual: node.operands.length },
|
||||||
|
severity: 'error',
|
||||||
|
node: node,
|
||||||
|
});
|
||||||
|
|
||||||
|
} else if (fnDecl.params.length < node.operands.length) {
|
||||||
|
|
||||||
|
self.diagnostics.add({
|
||||||
|
message: E_TOO_MANY_ARGUMENTS_FOR_FUNCTION_CALL,
|
||||||
|
args: { expected: fnDecl.params.length, actual: node.operands.length },
|
||||||
|
severity: 'error',
|
||||||
|
node: node,
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
const paramCount = fnDecl.params.length;
|
||||||
|
for (let i = 0; i < paramCount; i++) {
|
||||||
|
const arg = node.operands[i];
|
||||||
|
const param = fnDecl.params[i];
|
||||||
|
let argType = self.getTypeOfNode(arg);
|
||||||
|
let paramType = self.getTypeOfNode(param);
|
||||||
|
if (!self.isTypeAssignableTo(argType, paramType)) {
|
||||||
|
self.diagnostics.add({
|
||||||
|
message: E_INVALID_ARGUMENTS,
|
||||||
|
severity: 'error',
|
||||||
|
args: { name: fnDecl.name.text },
|
||||||
|
node: arg,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error(`Unknown node of type ${kindToString(node.kind)}.`);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function visitTypeExpressionn(node: BoltTypeExpression) {
|
||||||
|
|
||||||
|
switch (node.kind) {
|
||||||
|
|
||||||
|
case SyntaxKind.BoltReferenceTypeExpression:
|
||||||
|
{
|
||||||
|
if (self.resolveTypeReferenceExpression(node) === null) {
|
||||||
|
self.diagnostics.add({
|
||||||
|
message: E_TYPE_DECLARATION_NOT_FOUND,
|
||||||
|
args: { name: node.name.name.text },
|
||||||
|
severity: 'error',
|
||||||
|
node: node,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error(`Unknown node of type ${kindToString(node.kind)}.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function visitDeclaration(node: BoltDeclaration) {
|
||||||
|
|
||||||
|
switch (node.kind) {
|
||||||
|
|
||||||
|
case SyntaxKind.BoltRecordDeclaration:
|
||||||
|
{
|
||||||
|
if (node.members !== null) {
|
||||||
|
for (const member of node.members) {
|
||||||
|
if (member.kind === SyntaxKind.BoltRecordField) {
|
||||||
|
visitTypeExpressionn(member.type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SyntaxKind.BoltFunctionDeclaration:
|
||||||
|
{
|
||||||
|
let fnReturnType: Type = createAnyType();
|
||||||
|
|
||||||
|
if (node.returnType !== null) {
|
||||||
|
fnReturnType = self.getTypeOfNode(node.returnType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.body !== null) {
|
||||||
|
const returnStmts = getReturnStatementsInFunctionBody(node.body)
|
||||||
|
const validReturnTypes: Type[] = [];
|
||||||
|
for (const returnStmt of returnStmts) {
|
||||||
|
if (returnStmt.value === null) {
|
||||||
|
if (!isVoidType(fnReturnType)) {
|
||||||
|
self.diagnostics.add({
|
||||||
|
message: E_MUST_RETURN_A_VALUE,
|
||||||
|
node: returnStmt,
|
||||||
|
severity: 'error',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
checkExpressionMatchesType(returnStmt.value, fnReturnType);
|
||||||
|
}
|
||||||
|
//const returnType = self.getTypeOfNode(returnStmt);
|
||||||
|
//if (!self.isTypeAssignableTo(fnReturnType, returnType)) {
|
||||||
|
//self.diagnostics.add({
|
||||||
|
//severity: 'error',
|
||||||
|
//node: returnStmt.value !== null ? returnStmt.value : returnStmt,
|
||||||
|
//args: { left: fnReturnType, right: returnType },
|
||||||
|
//message: E_TYPES_NOT_ASSIGNABLE,
|
||||||
|
//});
|
||||||
|
//} else {
|
||||||
|
//validReturnTypes.push(returnType);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Sort the return types and find the largest types, eliminating types that fall under other types.
|
||||||
|
// Next, add the resulting types as type hints to `fnReturnType`.
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error(`Unknown node of type ${kindToString(node.kind)}.`);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkExpressionMatchesType(node: BoltExpression, expectedType: Type) {
|
||||||
|
switch (node.kind) {
|
||||||
|
case SyntaxKind.BoltMatchExpression:
|
||||||
|
{
|
||||||
|
for (const matchArm of node.arms) {
|
||||||
|
checkExpressionMatchesType(matchArm.body, expectedType);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
const actualType = self.getTypeOfNode(node);
|
||||||
|
if (!self.isTypeAssignableTo(expectedType, actualType)) {
|
||||||
|
self.diagnostics.add({
|
||||||
|
severity: 'error',
|
||||||
|
message: E_TYPES_NOT_ASSIGNABLE,
|
||||||
|
args: { left: expectedType, right: actualType },
|
||||||
|
node,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function visitStatement(node: BoltStatement) {
|
||||||
|
switch (node.kind) {
|
||||||
|
case SyntaxKind.BoltExpressionStatement:
|
||||||
|
// TODO check for values that should be unwrapped
|
||||||
|
visitExpression(node.expression);
|
||||||
|
break;
|
||||||
|
case SyntaxKind.BoltReturnStatement:
|
||||||
|
if (node.value !== null) {
|
||||||
|
visitExpression(node.value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error(`Unknown node of type ${kindToString(node.kind)}.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function visitSourceElement(node: BoltSourceElement) {
|
||||||
|
if (isBoltStatement(node)) {
|
||||||
|
visitStatement(node);
|
||||||
|
} else if (isBoltDeclaration(node)) {
|
||||||
|
visitDeclaration(node);
|
||||||
|
} else {
|
||||||
|
throw new Error(`Unknown node of kind ${kindToString(node)}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -185,6 +353,13 @@ export class TypeChecker {
|
||||||
}
|
}
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
case SyntaxKind.BoltReturnStatement:
|
||||||
|
{
|
||||||
|
if (node.value === null) {
|
||||||
|
return createVoidType();
|
||||||
|
}
|
||||||
|
return this.getTypeOfNode(node.value)
|
||||||
|
}
|
||||||
case SyntaxKind.BoltConstantExpression:
|
case SyntaxKind.BoltConstantExpression:
|
||||||
{
|
{
|
||||||
let type;
|
let type;
|
||||||
|
@ -200,6 +375,10 @@ export class TypeChecker {
|
||||||
assert(type !== null);
|
assert(type !== null);
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
case SyntaxKind.BoltMatchExpression:
|
||||||
|
{
|
||||||
|
return createVariantType(...node.arms.map(arm => this.getTypeOfNode(arm.body)));
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
throw new Error(`Could not derive type of node ${kindToString(node.kind)}.`);
|
throw new Error(`Could not derive type of node ${kindToString(node.kind)}.`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import {
|
||||||
|
|
||||||
export type BoltFunctionBody = BoltFunctionBodyElement[];
|
export type BoltFunctionBody = BoltFunctionBodyElement[];
|
||||||
|
|
||||||
export function getAllReturnStatements(body: BoltFunctionBody): BoltReturnStatement[] {
|
export function getReturnStatementsInFunctionBody(body: BoltFunctionBody): BoltReturnStatement[] {
|
||||||
|
|
||||||
const results: BoltReturnStatement[] = [];
|
const results: BoltReturnStatement[] = [];
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,11 @@ import {
|
||||||
createBoltSourceFile,
|
createBoltSourceFile,
|
||||||
BoltRecordField,
|
BoltRecordField,
|
||||||
setParents,
|
setParents,
|
||||||
|
BoltMatchExpression,
|
||||||
|
createBoltMatchArm,
|
||||||
|
BoltMatchArm,
|
||||||
|
createBoltMatchExpression,
|
||||||
|
createBoltExpressionPattern,
|
||||||
} from "./ast"
|
} from "./ast"
|
||||||
|
|
||||||
import { parseForeignLanguage } from "./foreign"
|
import { parseForeignLanguage } from "./foreign"
|
||||||
|
@ -81,6 +86,13 @@ export function isModifierKeyword(kind: SyntaxKind) {
|
||||||
|| kind === SyntaxKind.BoltForeignKeyword;
|
|| kind === SyntaxKind.BoltForeignKeyword;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function assertNoTokens(tokens: BoltTokenStream) {
|
||||||
|
const t0 = tokens.peek(1);
|
||||||
|
if (t0.kind !== SyntaxKind.EndOfFile) {
|
||||||
|
throw new ParseError(t0, [SyntaxKind.EndOfFile]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const KIND_EXPRESSION_T0 = [
|
const KIND_EXPRESSION_T0 = [
|
||||||
SyntaxKind.BoltStringLiteral,
|
SyntaxKind.BoltStringLiteral,
|
||||||
SyntaxKind.BoltIntegerLiteral,
|
SyntaxKind.BoltIntegerLiteral,
|
||||||
|
@ -156,13 +168,6 @@ export class Parser {
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
protected assertEmpty(tokens: BoltTokenStream) {
|
|
||||||
const t0 = tokens.peek(1);
|
|
||||||
if (t0.kind !== SyntaxKind.EndOfFile) {
|
|
||||||
throw new ParseError(t0, [SyntaxKind.EndOfFile]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public parse(kind: SyntaxKind, tokens: BoltTokenStream): BoltSyntax {
|
public parse(kind: SyntaxKind, tokens: BoltTokenStream): BoltSyntax {
|
||||||
return (this as any)['parse' + kindToString(kind).substring('Bolt'.length)](tokens);
|
return (this as any)['parse' + kindToString(kind).substring('Bolt'.length)](tokens);
|
||||||
}
|
}
|
||||||
|
@ -204,6 +209,17 @@ export class Parser {
|
||||||
const t0 = tokens.peek(1);
|
const t0 = tokens.peek(1);
|
||||||
if (t0.kind === SyntaxKind.BoltIdentifier) {
|
if (t0.kind === SyntaxKind.BoltIdentifier) {
|
||||||
return this.parseBindPattern(tokens);
|
return this.parseBindPattern(tokens);
|
||||||
|
} else if (t0.kind === SyntaxKind.BoltOperator && t0.text === '^') {
|
||||||
|
tokens.get();
|
||||||
|
const refExpr = this.parseReferenceExpression(tokens);
|
||||||
|
const result = createBoltExpressionPattern(refExpr);
|
||||||
|
setOrigNodeRange(result, t0, refExpr);
|
||||||
|
return result;
|
||||||
|
} else if (KIND_EXPRESSION_T0.indexOf(t0.kind) !== -1) {
|
||||||
|
const expr = this.parseExpression(tokens);
|
||||||
|
const result = createBoltExpressionPattern(expr);
|
||||||
|
setOrigNodeRange(result, expr, expr);
|
||||||
|
return result;
|
||||||
} else {
|
} else {
|
||||||
throw new ParseError(t0, [SyntaxKind.BoltIdentifier])
|
throw new ParseError(t0, [SyntaxKind.BoltIdentifier])
|
||||||
}
|
}
|
||||||
|
@ -328,9 +344,43 @@ export class Parser {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public parseMatchExpression(tokens: BoltTokenStream): BoltMatchExpression {
|
||||||
|
const t0 = tokens.get();
|
||||||
|
assertToken(t0, SyntaxKind.BoltMatchKeyword);
|
||||||
|
const expr = this.parseExpression(tokens);
|
||||||
|
const t1 = tokens.get();
|
||||||
|
assertToken(t1, SyntaxKind.BoltBraced);
|
||||||
|
const innerTokens = createTokenStream(t1);
|
||||||
|
const matchArms: BoltMatchArm[] = [];
|
||||||
|
while (true) {
|
||||||
|
const t2 = innerTokens.peek();
|
||||||
|
if (t2.kind === SyntaxKind.EndOfFile) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const pattern = this.parsePattern(innerTokens);
|
||||||
|
const t3 = innerTokens.get();
|
||||||
|
assertToken(t3, SyntaxKind.BoltRArrowAlt);
|
||||||
|
const expression = this.parseExpression(innerTokens);
|
||||||
|
const arm = createBoltMatchArm(pattern, expression);
|
||||||
|
setOrigNodeRange(arm, pattern, expression);
|
||||||
|
matchArms.push(arm);
|
||||||
|
const t4 = tokens.peek();
|
||||||
|
if (t4.kind === SyntaxKind.EndOfFile) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
assertToken(t4, SyntaxKind.BoltComma);
|
||||||
|
tokens.get();
|
||||||
|
}
|
||||||
|
const result = createBoltMatchExpression(expr, matchArms);
|
||||||
|
setOrigNodeRange(result, t0, t1);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
protected parsePrimitiveExpression(tokens: BoltTokenStream): BoltExpression {
|
protected parsePrimitiveExpression(tokens: BoltTokenStream): BoltExpression {
|
||||||
const t0 = tokens.peek();
|
const t0 = tokens.peek();
|
||||||
if (t0.kind === SyntaxKind.BoltIntegerLiteral || t0.kind === SyntaxKind.BoltStringLiteral) {
|
if (t0.kind === SyntaxKind.BoltMatchKeyword) {
|
||||||
|
return this.parseMatchExpression(tokens);
|
||||||
|
} else if (t0.kind === SyntaxKind.BoltIntegerLiteral || t0.kind === SyntaxKind.BoltStringLiteral) {
|
||||||
return this.parseConstantExpression(tokens);
|
return this.parseConstantExpression(tokens);
|
||||||
} else if (t0.kind === SyntaxKind.BoltIdentifier) {
|
} else if (t0.kind === SyntaxKind.BoltIdentifier) {
|
||||||
return this.parseReferenceExpression(tokens);
|
return this.parseReferenceExpression(tokens);
|
||||||
|
@ -714,7 +764,7 @@ export class Parser {
|
||||||
tokens.get();
|
tokens.get();
|
||||||
const innerTokens = createTokenStream(t0);
|
const innerTokens = createTokenStream(t0);
|
||||||
const param = this.parseParameter(innerTokens, i++)
|
const param = this.parseParameter(innerTokens, i++)
|
||||||
this.assertEmpty(innerTokens);
|
assertNoTokens(innerTokens);
|
||||||
return param
|
return param
|
||||||
} else {
|
} else {
|
||||||
throw new ParseError(t0, [SyntaxKind.BoltIdentifier, SyntaxKind.BoltParenthesized])
|
throw new ParseError(t0, [SyntaxKind.BoltIdentifier, SyntaxKind.BoltParenthesized])
|
||||||
|
@ -794,7 +844,7 @@ export class Parser {
|
||||||
tokens.get();
|
tokens.get();
|
||||||
switch (target) {
|
switch (target) {
|
||||||
case "Bolt":
|
case "Bolt":
|
||||||
body = this.parseStatements(tokens);
|
body = this.parseStatements(createTokenStream(t3));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
body = parseForeignLanguage(target, t3.text, t3.span!.file, t3.span!.start);
|
body = parseForeignLanguage(target, t3.text, t3.span!.file, t3.span!.start);
|
||||||
|
@ -870,8 +920,7 @@ export class Parser {
|
||||||
let t0 = tokens.peek(1);
|
let t0 = tokens.peek(1);
|
||||||
let i = 1;
|
let i = 1;
|
||||||
if (t0.kind === SyntaxKind.BoltPubKeyword) {
|
if (t0.kind === SyntaxKind.BoltPubKeyword) {
|
||||||
i += 1;
|
t0 = tokens.peek(++i);
|
||||||
t0 = tokens.peek(i);
|
|
||||||
if (t0.kind !== SyntaxKind.BoltForeignKeyword) {
|
if (t0.kind !== SyntaxKind.BoltForeignKeyword) {
|
||||||
if (KIND_DECLARATION_KEYWORD.indexOf(t0.kind) === -1) {
|
if (KIND_DECLARATION_KEYWORD.indexOf(t0.kind) === -1) {
|
||||||
throw new ParseError(t0, KIND_DECLARATION_KEYWORD);
|
throw new ParseError(t0, KIND_DECLARATION_KEYWORD);
|
||||||
|
@ -918,8 +967,8 @@ export class Parser {
|
||||||
}
|
}
|
||||||
if (t0.kind === SyntaxKind.BoltForeignKeyword) {
|
if (t0.kind === SyntaxKind.BoltForeignKeyword) {
|
||||||
mustBeFunctionOrVariable = true;
|
mustBeFunctionOrVariable = true;
|
||||||
i++;
|
i += 2;
|
||||||
t0 = tokens.peek(++i);
|
t0 = tokens.peek(i);
|
||||||
}
|
}
|
||||||
if (mustBeFunctionOrVariable
|
if (mustBeFunctionOrVariable
|
||||||
&& t0.kind !== SyntaxKind.BoltStructKeyword
|
&& t0.kind !== SyntaxKind.BoltStructKeyword
|
||||||
|
@ -1015,11 +1064,11 @@ export class Parser {
|
||||||
|
|
||||||
const operator = this.parsePrimitiveExpression(tokens)
|
const operator = this.parsePrimitiveExpression(tokens)
|
||||||
|
|
||||||
const t2 = tokens.get();
|
const t2 = tokens.peek();
|
||||||
if (t2.kind === SyntaxKind.EndOfFile) {
|
if (t2.kind !== SyntaxKind.BoltParenthesized) {
|
||||||
return operator;
|
return operator;
|
||||||
}
|
}
|
||||||
assertToken(t2, SyntaxKind.BoltParenthesized);
|
tokens.get();
|
||||||
|
|
||||||
const args: BoltExpression[] = []
|
const args: BoltExpression[] = []
|
||||||
const innerTokens = createTokenStream(t2);
|
const innerTokens = createTokenStream(t2);
|
||||||
|
@ -1197,4 +1246,4 @@ export function parseSourceFile(filepath: string): BoltSourceFile {
|
||||||
setParents(sourceFile);
|
setParents(sourceFile);
|
||||||
return sourceFile;
|
return sourceFile;
|
||||||
}
|
}
|
||||||
|
;
|
||||||
|
|
|
@ -11,9 +11,8 @@ import {
|
||||||
setParents,
|
setParents,
|
||||||
SyntaxKind,
|
SyntaxKind,
|
||||||
BoltToken,
|
BoltToken,
|
||||||
BoltSentence,
|
createBoltRArrowAlt,
|
||||||
createEndOfFile,
|
createEndOfFile,
|
||||||
createBoltSentence,
|
|
||||||
createBoltIdentifier,
|
createBoltIdentifier,
|
||||||
createBoltRArrow,
|
createBoltRArrow,
|
||||||
createBoltOperator,
|
createBoltOperator,
|
||||||
|
@ -39,16 +38,14 @@ import {
|
||||||
createBoltFnKeyword,
|
createBoltFnKeyword,
|
||||||
createBoltLArrow,
|
createBoltLArrow,
|
||||||
createBoltDotDot,
|
createBoltDotDot,
|
||||||
createJSIdentifier,
|
|
||||||
JSToken,
|
|
||||||
createBoltLtSign,
|
createBoltLtSign,
|
||||||
createBoltGtSign,
|
createBoltGtSign,
|
||||||
createBoltModKeyword,
|
createBoltModKeyword,
|
||||||
createBoltTypeKeyword,
|
createBoltTypeKeyword,
|
||||||
createBoltForKeyword,
|
createBoltForKeyword,
|
||||||
createBoltTraitDeclaration,
|
|
||||||
createBoltTraitKeyword,
|
createBoltTraitKeyword,
|
||||||
createBoltImplKeyword,
|
createBoltImplKeyword,
|
||||||
|
createBoltMatchKeyword,
|
||||||
} from "./ast"
|
} from "./ast"
|
||||||
|
|
||||||
export enum PunctType {
|
export enum PunctType {
|
||||||
|
@ -297,6 +294,7 @@ export class Scanner {
|
||||||
case 'mod': return createBoltModKeyword(span);
|
case 'mod': return createBoltModKeyword(span);
|
||||||
case 'fn': return createBoltFnKeyword(span);
|
case 'fn': return createBoltFnKeyword(span);
|
||||||
case 'return': return createBoltReturnKeyword(span);
|
case 'return': return createBoltReturnKeyword(span);
|
||||||
|
case 'match': return createBoltMatchKeyword(span);
|
||||||
case 'yield': return createBoltYieldKeyword(span);
|
case 'yield': return createBoltYieldKeyword(span);
|
||||||
case 'for': return createBoltForKeyword(span);
|
case 'for': return createBoltForKeyword(span);
|
||||||
case 'trait': return createBoltTraitKeyword(span);
|
case 'trait': return createBoltTraitKeyword(span);
|
||||||
|
@ -318,6 +316,7 @@ export class Scanner {
|
||||||
|
|
||||||
switch (text) {
|
switch (text) {
|
||||||
case '->': return createBoltRArrow(span);
|
case '->': return createBoltRArrow(span);
|
||||||
|
case '=>': return createBoltRArrowAlt(span);
|
||||||
case '<-': return createBoltLArrow(span);
|
case '<-': return createBoltLArrow(span);
|
||||||
case '<': return createBoltLtSign(span);
|
case '<': return createBoltLtSign(span);
|
||||||
case '>': return createBoltGtSign(span);
|
case '>': return createBoltGtSign(span);
|
||||||
|
|
28
src/types.ts
28
src/types.ts
|
@ -98,6 +98,10 @@ export class VariantType extends TypeBase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createVariantType(...elementTypes: Type[]): VariantType {
|
||||||
|
return new VariantType(elementTypes);
|
||||||
|
}
|
||||||
|
|
||||||
export function isVariantType(value: any): value is VariantType {
|
export function isVariantType(value: any): value is VariantType {
|
||||||
return value instanceof VariantType;
|
return value instanceof VariantType;
|
||||||
}
|
}
|
||||||
|
@ -140,6 +144,30 @@ export class TupleType extends TypeBase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createTupleType(...elementTypes: Type[]) {
|
||||||
|
return new TupleType(elementTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isTupleType(value: any): value is TupleType {
|
||||||
|
return value.kind === TypeKind.TupleType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createVoidType() {
|
||||||
|
return createTupleType();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isVoidType(value: any) {
|
||||||
|
return isTupleType(value) && value.elementTypes.length === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function narrowType(outer: Type, inner: Type): Type {
|
||||||
|
if (isAnyType(outer) || isNeverType(inner)) {
|
||||||
|
return inner;
|
||||||
|
}
|
||||||
|
// TODO cover the other cases
|
||||||
|
return outer;
|
||||||
|
}
|
||||||
|
|
||||||
export function intersectTypes(a: Type, b: Type): Type {
|
export function intersectTypes(a: Type, b: Type): Type {
|
||||||
if (isNeverType(a) || isNeverType(b)) {
|
if (isNeverType(a) || isNeverType(b)) {
|
||||||
return new NeverType();
|
return new NeverType();
|
||||||
|
|
|
@ -351,6 +351,8 @@ export function describeKind(kind: SyntaxKind): string {
|
||||||
return "'for'";
|
return "'for'";
|
||||||
case SyntaxKind.JSTryKeyword:
|
case SyntaxKind.JSTryKeyword:
|
||||||
return "'try'";
|
return "'try'";
|
||||||
|
case SyntaxKind.BoltRArrowAlt:
|
||||||
|
return "'=>'";
|
||||||
default:
|
default:
|
||||||
throw new Error(`failed to describe ${kindToString(kind)}`)
|
throw new Error(`failed to describe ${kindToString(kind)}`)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue