Skip to content

BigInt support #25886

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Nov 5, 2018
6 changes: 6 additions & 0 deletions src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3702,6 +3702,10 @@ namespace ts {
}
break;

case SyntaxKind.BigIntLiteral:
transformFlags |= TransformFlags.AssertESNext;
break;

case SyntaxKind.ForOfStatement:
// This node is either ES2015 syntax or ES2017 syntax (if it is a for-await-of).
if ((<ForOfStatement>node).awaitModifier) {
Expand All @@ -3718,6 +3722,7 @@ namespace ts {

case SyntaxKind.AnyKeyword:
case SyntaxKind.NumberKeyword:
case SyntaxKind.BigIntKeyword:
case SyntaxKind.NeverKeyword:
case SyntaxKind.ObjectKeyword:
case SyntaxKind.StringKeyword:
Expand Down Expand Up @@ -3926,6 +3931,7 @@ namespace ts {
return TransformFlags.MethodOrAccessorExcludes;
case SyntaxKind.AnyKeyword:
case SyntaxKind.NumberKeyword:
case SyntaxKind.BigIntKeyword:
case SyntaxKind.NeverKeyword:
case SyntaxKind.StringKeyword:
case SyntaxKind.ObjectKeyword:
Expand Down
292 changes: 226 additions & 66 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

9 changes: 8 additions & 1 deletion src/compiler/commandLineParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ namespace ts {
["esnext.array", "lib.esnext.array.d.ts"],
["esnext.symbol", "lib.esnext.symbol.d.ts"],
["esnext.asynciterable", "lib.esnext.asynciterable.d.ts"],
["esnext.intl", "lib.esnext.intl.d.ts"]
["esnext.intl", "lib.esnext.intl.d.ts"],
["esnext.bigint", "lib.esnext.bigint.d.ts"]
];

/**
Expand Down Expand Up @@ -583,6 +584,12 @@ namespace ts {
category: Diagnostics.Experimental_Options,
description: Diagnostics.Enables_experimental_support_for_emitting_type_metadata_for_decorators
},
{
name: "experimentalBigInt",
type: "boolean",
category: Diagnostics.Experimental_Options,
description: Diagnostics.Enables_experimental_support_for_ESNext_BigInt_literals
},

// Advanced
{
Expand Down
22 changes: 19 additions & 3 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1011,6 +1011,10 @@
"category": "Message",
"code": 1350
},
"Experimental support for BigInt is a feature that is subject to change in a future release. Set the 'experimentalBigInt' option to remove this warning.": {
"category": "Error",
"code": 1351
},

"Duplicate identifier '{0}'.": {
"category": "Error",
Expand Down Expand Up @@ -1236,7 +1240,7 @@
"category": "Error",
"code": 2355
},
"An arithmetic operand must be of type 'any', 'number' or an enum type.": {
"An arithmetic operand must be of type 'any', 'number', 'bigint' or an enum type.": {
"category": "Error",
"code": 2356
},
Expand All @@ -1260,11 +1264,11 @@
"category": "Error",
"code": 2361
},
"The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type.": {
"The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.": {
"category": "Error",
"code": 2362
},
"The right-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type.": {
"The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.": {
"category": "Error",
"code": 2363
},
Expand Down Expand Up @@ -2497,6 +2501,14 @@
"category": "Error",
"code": 2735
},
"Operator '{0}' cannot be applied to type '{1}'.": {
"category": "Error",
"code": 2736
},
"BigInt literals are not available when targetting lower than ESNext.": {
"category": "Error",
"code": 2737
},

"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
Expand Down Expand Up @@ -3905,6 +3917,10 @@
"category": "Error",
"code": 6370
},
"Enables experimental support for ESNext BigInt literals.": {
"category": "Message",
"code": 6371
},

"The expected type comes from property '{0}' which is declared here on type '{1}'": {
"category": "Message",
Expand Down
6 changes: 4 additions & 2 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -905,7 +905,8 @@ namespace ts {
switch (node.kind) {
// Literals
case SyntaxKind.NumericLiteral:
return emitNumericLiteral(<NumericLiteral>node);
case SyntaxKind.BigIntLiteral:
return emitNumericOrBigIntLiteral(<NumericLiteral | BigIntLiteral>node);

case SyntaxKind.StringLiteral:
case SyntaxKind.RegularExpressionLiteral:
Expand Down Expand Up @@ -1068,7 +1069,8 @@ namespace ts {
//

// SyntaxKind.NumericLiteral
function emitNumericLiteral(node: NumericLiteral) {
// SyntaxKind.BigIntLiteral
function emitNumericOrBigIntLiteral(node: NumericLiteral | BigIntLiteral) {
emitLiteral(node);
}

Expand Down
16 changes: 13 additions & 3 deletions src/compiler/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,16 @@ namespace ts {
/* @internal */ export function createLiteral(value: string | StringLiteral | NoSubstitutionTemplateLiteral | NumericLiteral | Identifier, isSingleQuote: boolean): StringLiteral; // tslint:disable-line unified-signatures
/** If a node is passed, creates a string literal whose source text is read from a source node during emit. */
export function createLiteral(value: string | StringLiteral | NoSubstitutionTemplateLiteral | NumericLiteral | Identifier): StringLiteral;
export function createLiteral(value: number): NumericLiteral;
export function createLiteral(value: number | PseudoBigInt): NumericLiteral;
export function createLiteral(value: boolean): BooleanLiteral;
export function createLiteral(value: string | number | boolean): PrimaryExpression;
export function createLiteral(value: string | number | boolean | StringLiteral | NoSubstitutionTemplateLiteral | NumericLiteral | Identifier, isSingleQuote?: boolean): PrimaryExpression {
export function createLiteral(value: string | number | PseudoBigInt | boolean): PrimaryExpression;
export function createLiteral(value: string | number | PseudoBigInt | boolean | StringLiteral | NoSubstitutionTemplateLiteral | NumericLiteral | Identifier, isSingleQuote?: boolean): PrimaryExpression {
if (typeof value === "number") {
return createNumericLiteral(value + "");
}
if (typeof value === "object" && "base10Value" in value) { // PseudoBigInt
return createBigIntLiteral(pseudoBigIntToString(value) + "n");
}
if (typeof value === "boolean") {
return value ? createTrue() : createFalse();
}
Expand All @@ -93,6 +96,12 @@ namespace ts {
return node;
}

export function createBigIntLiteral(value: string): BigIntLiteral {
const node = <BigIntLiteral>createSynthesizedNode(SyntaxKind.BigIntLiteral);
node.text = value;
return node;
}

export function createStringLiteral(text: string): StringLiteral {
const node = <StringLiteral>createSynthesizedNode(SyntaxKind.StringLiteral);
node.text = text;
Expand Down Expand Up @@ -3467,6 +3476,7 @@ namespace ts {
return cacheIdentifiers;
case SyntaxKind.ThisKeyword:
case SyntaxKind.NumericLiteral:
case SyntaxKind.BigIntLiteral:
case SyntaxKind.StringLiteral:
return false;
case SyntaxKind.ArrayLiteralExpression:
Expand Down
20 changes: 13 additions & 7 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2247,8 +2247,7 @@ namespace ts {

function parseLiteralLikeNode(kind: SyntaxKind): LiteralExpression | LiteralLikeNode {
const node = <LiteralExpression>createNode(kind);
const text = scanner.getTokenValue();
node.text = text;
node.text = scanner.getTokenValue();

if (scanner.hasExtendedUnicodeEscape()) {
node.hasExtendedUnicodeEscape = true;
Expand Down Expand Up @@ -2892,8 +2891,9 @@ namespace ts {
return finishNode(node);
}

function nextTokenIsNumericLiteral() {
return nextToken() === SyntaxKind.NumericLiteral;
function nextTokenIsNumericOrBigIntLiteral() {
nextToken();
return token() === SyntaxKind.NumericLiteral || token() === SyntaxKind.BigIntLiteral;
}

function parseNonArrayType(): TypeNode {
Expand All @@ -2902,6 +2902,7 @@ namespace ts {
case SyntaxKind.UnknownKeyword:
case SyntaxKind.StringKeyword:
case SyntaxKind.NumberKeyword:
case SyntaxKind.BigIntKeyword:
case SyntaxKind.SymbolKeyword:
case SyntaxKind.BooleanKeyword:
case SyntaxKind.UndefinedKeyword:
Expand All @@ -2922,11 +2923,12 @@ namespace ts {
case SyntaxKind.NoSubstitutionTemplateLiteral:
case SyntaxKind.StringLiteral:
case SyntaxKind.NumericLiteral:
case SyntaxKind.BigIntLiteral:
case SyntaxKind.TrueKeyword:
case SyntaxKind.FalseKeyword:
return parseLiteralTypeNode();
case SyntaxKind.MinusToken:
return lookAhead(nextTokenIsNumericLiteral) ? parseLiteralTypeNode(/*negative*/ true) : parseTypeReference();
return lookAhead(nextTokenIsNumericOrBigIntLiteral) ? parseLiteralTypeNode(/*negative*/ true) : parseTypeReference();
case SyntaxKind.VoidKeyword:
case SyntaxKind.NullKeyword:
return parseTokenNode<TypeNode>();
Expand Down Expand Up @@ -2960,6 +2962,7 @@ namespace ts {
case SyntaxKind.UnknownKeyword:
case SyntaxKind.StringKeyword:
case SyntaxKind.NumberKeyword:
case SyntaxKind.BigIntKeyword:
case SyntaxKind.BooleanKeyword:
case SyntaxKind.SymbolKeyword:
case SyntaxKind.UniqueKeyword:
Expand All @@ -2977,6 +2980,7 @@ namespace ts {
case SyntaxKind.NewKeyword:
case SyntaxKind.StringLiteral:
case SyntaxKind.NumericLiteral:
case SyntaxKind.BigIntLiteral:
case SyntaxKind.TrueKeyword:
case SyntaxKind.FalseKeyword:
case SyntaxKind.ObjectKeyword:
Expand All @@ -2990,7 +2994,7 @@ namespace ts {
case SyntaxKind.FunctionKeyword:
return !inStartOfParameter;
case SyntaxKind.MinusToken:
return !inStartOfParameter && lookAhead(nextTokenIsNumericLiteral);
return !inStartOfParameter && lookAhead(nextTokenIsNumericOrBigIntLiteral);
case SyntaxKind.OpenParenToken:
// Only consider '(' the start of a type if followed by ')', '...', an identifier, a modifier,
// or something that starts a type. We don't want to consider things like '(1)' a type.
Expand Down Expand Up @@ -3215,6 +3219,7 @@ namespace ts {
case SyntaxKind.TrueKeyword:
case SyntaxKind.FalseKeyword:
case SyntaxKind.NumericLiteral:
case SyntaxKind.BigIntLiteral:
case SyntaxKind.StringLiteral:
case SyntaxKind.NoSubstitutionTemplateLiteral:
case SyntaxKind.TemplateHead:
Expand Down Expand Up @@ -4624,6 +4629,7 @@ namespace ts {
function parsePrimaryExpression(): PrimaryExpression {
switch (token()) {
case SyntaxKind.NumericLiteral:
case SyntaxKind.BigIntLiteral:
case SyntaxKind.StringLiteral:
case SyntaxKind.NoSubstitutionTemplateLiteral:
return parseLiteralNode();
Expand Down Expand Up @@ -5139,7 +5145,7 @@ namespace ts {

function nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine() {
nextToken();
return (tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.NumericLiteral || token() === SyntaxKind.StringLiteral) && !scanner.hasPrecedingLineBreak();
return (tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.NumericLiteral || token() === SyntaxKind.BigIntLiteral || token() === SyntaxKind.StringLiteral) && !scanner.hasPrecedingLineBreak();
}

function isDeclaration(): boolean {
Expand Down
Loading