From ac2a118f075f9382cc84c6fee94fdee24835d058 Mon Sep 17 00:00:00 2001 From: Caleb Sander Date: Sat, 29 Sep 2018 14:02:44 -0700 Subject: [PATCH] Add bigint type --- src/compiler/checker.ts | 245 ++++++++++++++++++++++++-------- src/compiler/factory.ts | 11 +- src/compiler/transformers/ts.ts | 3 + src/compiler/types.ts | 82 ++++++----- src/compiler/utilities.ts | 2 + src/services/completions.ts | 9 +- 6 files changed, 254 insertions(+), 98 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e50239e622f..5e03f1b3987 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -403,6 +403,7 @@ namespace ts { const nullWideningType = strictNullChecks ? nullType : createIntrinsicType(TypeFlags.Null | TypeFlags.ContainsWideningType, "null"); const stringType = createIntrinsicType(TypeFlags.String, "string"); const numberType = createIntrinsicType(TypeFlags.Number, "number"); + const bigintType = createIntrinsicType(TypeFlags.BigInt, "bigint"); const falseType = createIntrinsicType(TypeFlags.BooleanLiteral, "false") as FreshableIntrinsicType; const regularFalseType = createIntrinsicType(TypeFlags.BooleanLiteral, "false") as FreshableIntrinsicType; const trueType = createIntrinsicType(TypeFlags.BooleanLiteral, "true") as FreshableIntrinsicType; @@ -427,6 +428,7 @@ namespace ts { const nonPrimitiveType = createIntrinsicType(TypeFlags.NonPrimitive, "object"); const stringNumberSymbolType = getUnionType([stringType, numberType, esSymbolType]); const keyofConstraintType = keyofStringsOnly ? stringType : stringNumberSymbolType; + const numberOrBigIntType = getUnionType([numberType, bigintType]); const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); @@ -518,6 +520,7 @@ namespace ts { let deferredGlobalTemplateStringsArrayType: ObjectType; let deferredGlobalImportMetaType: ObjectType; let deferredGlobalExtractSymbol: Symbol; + let deferredGlobalBigIntType: ObjectType; const allPotentiallyUnusedIdentifiers = createMap(); // key is file name @@ -528,6 +531,7 @@ namespace ts { const emptyStringType = getLiteralType(""); const zeroType = getLiteralType(0); + const zeroBigIntType = getLiteralType({ negative: false, base10Value: "0" }); const resolutionTargets: TypeSystemEntity[] = []; const resolutionResults: boolean[] = []; @@ -556,31 +560,33 @@ namespace ts { None = 0, TypeofEQString = 1 << 0, // typeof x === "string" TypeofEQNumber = 1 << 1, // typeof x === "number" - TypeofEQBoolean = 1 << 2, // typeof x === "boolean" - TypeofEQSymbol = 1 << 3, // typeof x === "symbol" - TypeofEQObject = 1 << 4, // typeof x === "object" - TypeofEQFunction = 1 << 5, // typeof x === "function" - TypeofEQHostObject = 1 << 6, // typeof x === "xxx" - TypeofNEString = 1 << 7, // typeof x !== "string" - TypeofNENumber = 1 << 8, // typeof x !== "number" - TypeofNEBoolean = 1 << 9, // typeof x !== "boolean" - TypeofNESymbol = 1 << 10, // typeof x !== "symbol" - TypeofNEObject = 1 << 11, // typeof x !== "object" - TypeofNEFunction = 1 << 12, // typeof x !== "function" - TypeofNEHostObject = 1 << 13, // typeof x !== "xxx" - EQUndefined = 1 << 14, // x === undefined - EQNull = 1 << 15, // x === null - EQUndefinedOrNull = 1 << 16, // x === undefined / x === null - NEUndefined = 1 << 17, // x !== undefined - NENull = 1 << 18, // x !== null - NEUndefinedOrNull = 1 << 19, // x != undefined / x != null - Truthy = 1 << 20, // x - Falsy = 1 << 21, // !x - All = (1 << 22) - 1, + TypeofEQBigInt = 1 << 2, // typeof x === "bigint" + TypeofEQBoolean = 1 << 3, // typeof x === "boolean" + TypeofEQSymbol = 1 << 4, // typeof x === "symbol" + TypeofEQObject = 1 << 5, // typeof x === "object" + TypeofEQFunction = 1 << 6, // typeof x === "function" + TypeofEQHostObject = 1 << 7, // typeof x === "xxx" + TypeofNEString = 1 << 8, // typeof x !== "string" + TypeofNENumber = 1 << 9, // typeof x !== "number" + TypeofNEBigInt = 1 << 10, // typeof x !== "bigint" + TypeofNEBoolean = 1 << 11, // typeof x !== "boolean" + TypeofNESymbol = 1 << 12, // typeof x !== "symbol" + TypeofNEObject = 1 << 13, // typeof x !== "object" + TypeofNEFunction = 1 << 14, // typeof x !== "function" + TypeofNEHostObject = 1 << 15, // typeof x !== "xxx" + EQUndefined = 1 << 16, // x === undefined + EQNull = 1 << 17, // x === null + EQUndefinedOrNull = 1 << 18, // x === undefined / x === null + NEUndefined = 1 << 19, // x !== undefined + NENull = 1 << 20, // x !== null + NEUndefinedOrNull = 1 << 21, // x != undefined / x != null + Truthy = 1 << 22, // x + Falsy = 1 << 23, // !x + All = (1 << 24) - 1, // The following members encode facts about particular kinds of types for use in the getTypeFacts function. // The presence of a particular fact means that the given test is true for some (and possibly all) values // of that kind of type. - BaseStringStrictFacts = TypeofEQString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull, + BaseStringStrictFacts = TypeofEQString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull, BaseStringFacts = BaseStringStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, StringStrictFacts = BaseStringStrictFacts | Truthy | Falsy, StringFacts = BaseStringFacts | Truthy, @@ -588,15 +594,23 @@ namespace ts { EmptyStringFacts = BaseStringFacts, NonEmptyStringStrictFacts = BaseStringStrictFacts | Truthy, NonEmptyStringFacts = BaseStringFacts | Truthy, - BaseNumberStrictFacts = TypeofEQNumber | TypeofNEString | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull, + BaseNumberStrictFacts = TypeofEQNumber | TypeofNEString | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull, BaseNumberFacts = BaseNumberStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, NumberStrictFacts = BaseNumberStrictFacts | Truthy | Falsy, NumberFacts = BaseNumberFacts | Truthy, - ZeroStrictFacts = BaseNumberStrictFacts | Falsy, - ZeroFacts = BaseNumberFacts, - NonZeroStrictFacts = BaseNumberStrictFacts | Truthy, - NonZeroFacts = BaseNumberFacts | Truthy, - BaseBooleanStrictFacts = TypeofEQBoolean | TypeofNEString | TypeofNENumber | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull, + ZeroNumberStrictFacts = BaseNumberStrictFacts | Falsy, + ZeroNumberFacts = BaseNumberFacts, + NonZeroNumberStrictFacts = BaseNumberStrictFacts | Truthy, + NonZeroNumberFacts = BaseNumberFacts | Truthy, + BaseBigIntStrictFacts = TypeofEQBigInt | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull, + BaseBigIntFacts = BaseBigIntStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, + BigIntStrictFacts = BaseBigIntStrictFacts | Truthy | Falsy, + BigIntFacts = BaseBigIntFacts | Truthy, + ZeroBigIntStrictFacts = BaseBigIntStrictFacts | Falsy, + ZeroBigIntFacts = BaseBigIntFacts, + NonZeroBigIntStrictFacts = BaseBigIntStrictFacts | Truthy, + NonZeroBigIntFacts = BaseBigIntFacts | Truthy, + BaseBooleanStrictFacts = TypeofEQBoolean | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull, BaseBooleanFacts = BaseBooleanStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, BooleanStrictFacts = BaseBooleanStrictFacts | Truthy | Falsy, BooleanFacts = BaseBooleanFacts | Truthy, @@ -604,14 +618,14 @@ namespace ts { FalseFacts = BaseBooleanFacts, TrueStrictFacts = BaseBooleanStrictFacts | Truthy, TrueFacts = BaseBooleanFacts | Truthy, - SymbolStrictFacts = TypeofEQSymbol | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy, + SymbolStrictFacts = TypeofEQSymbol | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy, SymbolFacts = SymbolStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, - ObjectStrictFacts = TypeofEQObject | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | NEUndefined | NENull | NEUndefinedOrNull | Truthy, + ObjectStrictFacts = TypeofEQObject | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | NEUndefined | NENull | NEUndefinedOrNull | Truthy, ObjectFacts = ObjectStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, - FunctionStrictFacts = TypeofEQFunction | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy, + FunctionStrictFacts = TypeofEQFunction | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy, FunctionFacts = FunctionStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, - UndefinedFacts = TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQUndefinedOrNull | NENull | Falsy, - NullFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | TypeofNEHostObject | EQNull | EQUndefinedOrNull | NEUndefined | Falsy, + UndefinedFacts = TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQUndefinedOrNull | NENull | Falsy, + NullFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | TypeofNEHostObject | EQNull | EQUndefinedOrNull | NEUndefined | Falsy, EmptyObjectStrictFacts = All & ~(EQUndefined | EQNull | EQUndefinedOrNull), EmptyObjectFacts = All, } @@ -619,6 +633,7 @@ namespace ts { const typeofEQFacts = createMapFromTemplate({ string: TypeFacts.TypeofEQString, number: TypeFacts.TypeofEQNumber, + bigint: TypeFacts.TypeofEQBigInt, boolean: TypeFacts.TypeofEQBoolean, symbol: TypeFacts.TypeofEQSymbol, undefined: TypeFacts.EQUndefined, @@ -628,6 +643,7 @@ namespace ts { const typeofNEFacts = createMapFromTemplate({ string: TypeFacts.TypeofNEString, number: TypeFacts.TypeofNENumber, + bigint: TypeFacts.TypeofNEBigInt, boolean: TypeFacts.TypeofNEBoolean, symbol: TypeFacts.TypeofNESymbol, undefined: TypeFacts.NEUndefined, @@ -637,6 +653,7 @@ namespace ts { const typeofTypesByName = createMapFromTemplate({ string: stringType, number: numberType, + bigint: bigintType, boolean: booleanType, symbol: esSymbolType, undefined: undefinedType @@ -3217,6 +3234,10 @@ namespace ts { context.approximateLength += 6; return createKeywordTypeNode(SyntaxKind.NumberKeyword); } + if (type.flags & TypeFlags.BigInt) { + context.approximateLength += 6; + return createKeywordTypeNode(SyntaxKind.BigIntKeyword); + } if (type.flags & TypeFlags.Boolean) { context.approximateLength += 7; return createKeywordTypeNode(SyntaxKind.BooleanKeyword); @@ -3243,6 +3264,10 @@ namespace ts { context.approximateLength += (("" + (type).value).length); return createLiteralTypeNode((createLiteral((type).value))); } + if (type.flags & TypeFlags.BigIntLiteral) { + context.approximateLength += (pseudoBigIntToString((type).value).length) + 1; + return createLiteralTypeNode((createLiteral((type).value))); + } if (type.flags & TypeFlags.BooleanLiteral) { context.approximateLength += (type).intrinsicName.length; return (type).intrinsicName === "true" ? createTrue() : createFalse(); @@ -6066,6 +6091,7 @@ namespace ts { case SyntaxKind.UnknownKeyword: case SyntaxKind.StringKeyword: case SyntaxKind.NumberKeyword: + case SyntaxKind.BigIntKeyword: case SyntaxKind.BooleanKeyword: case SyntaxKind.SymbolKeyword: case SyntaxKind.ObjectKeyword: @@ -7313,6 +7339,7 @@ namespace ts { t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(t) : t.flags & TypeFlags.StringLike ? globalStringType : t.flags & TypeFlags.NumberLike ? globalNumberType : + t.flags & TypeFlags.BigIntLike ? getGlobalBigIntType(/*reportErrors*/ languageVersion >= ScriptTarget.ESNext) : t.flags & TypeFlags.BooleanLike ? globalBooleanType : t.flags & TypeFlags.ESSymbolLike ? getGlobalESSymbolType(/*reportErrors*/ languageVersion >= ScriptTarget.ES2015) : t.flags & TypeFlags.NonPrimitive ? emptyObjectType : @@ -8650,6 +8677,10 @@ namespace ts { return deferredGlobalExtractSymbol || (deferredGlobalExtractSymbol = getGlobalSymbol("Extract" as __String, SymbolFlags.TypeAlias, Diagnostics.Cannot_find_global_type_0)!); // TODO: GH#18217 } + function getGlobalBigIntType(reportErrors: boolean) { + return deferredGlobalBigIntType || (deferredGlobalBigIntType = getGlobalType("BigInt" as __String, /*arity*/ 0, reportErrors)) || emptyObjectType; + } + /** * Instantiates a global type that is generic with some element type, and returns that instantiation. */ @@ -8830,6 +8861,7 @@ namespace ts { combined & TypeFlags.NonPrimitive && combined & (TypeFlags.DisjointDomains & ~TypeFlags.NonPrimitive) || combined & TypeFlags.StringLike && combined & (TypeFlags.DisjointDomains & ~TypeFlags.StringLike) || combined & TypeFlags.NumberLike && combined & (TypeFlags.DisjointDomains & ~TypeFlags.NumberLike) || + combined & TypeFlags.BigIntLike && combined & (TypeFlags.DisjointDomains & ~TypeFlags.BigIntLike) || combined & TypeFlags.ESSymbolLike && combined & (TypeFlags.DisjointDomains & ~TypeFlags.ESSymbolLike) || combined & TypeFlags.VoidLike && combined & (TypeFlags.DisjointDomains & ~TypeFlags.VoidLike)) { return true; @@ -8922,6 +8954,7 @@ namespace ts { const remove = t.flags & TypeFlags.StringLiteral && includes & TypeFlags.String || t.flags & TypeFlags.NumberLiteral && includes & TypeFlags.Number || + t.flags & TypeFlags.BigIntLiteral && includes & TypeFlags.BigInt || t.flags & TypeFlags.UniqueESSymbol && includes & TypeFlags.ESSymbol || t.flags & TypeFlags.Literal && t.flags & TypeFlags.FreshLiteral && containsType(types, (t).regularType); if (remove) { @@ -9079,6 +9112,7 @@ namespace ts { const remove = t.flags & TypeFlags.String && includes & TypeFlags.StringLiteral || t.flags & TypeFlags.Number && includes & TypeFlags.NumberLiteral || + t.flags & TypeFlags.BigInt && includes & TypeFlags.BigIntLiteral || t.flags & TypeFlags.ESSymbol && includes & TypeFlags.UniqueESSymbol; if (remove) { orderedRemoveItemAt(types, i); @@ -9094,6 +9128,7 @@ namespace ts { if (!containsType(u.types, type)) { const primitive = type.flags & TypeFlags.StringLiteral ? stringType : type.flags & TypeFlags.NumberLiteral ? numberType : + type.flags & TypeFlags.BigIntLiteral ? bigintType : type.flags & TypeFlags.UniqueESSymbol ? esSymbolType : undefined; if (!primitive || !containsType(u.types, primitive)) { @@ -9170,6 +9205,7 @@ namespace ts { } if (includes & TypeFlags.String && includes & TypeFlags.StringLiteral || includes & TypeFlags.Number && includes & TypeFlags.NumberLiteral || + includes & TypeFlags.BigInt && includes & TypeFlags.BigIntLiteral || includes & TypeFlags.ESSymbol && includes & TypeFlags.UniqueESSymbol) { removeRedundantPrimitiveTypes(typeSet, includes); } @@ -9232,13 +9268,24 @@ namespace ts { type.resolvedIndexType || (type.resolvedIndexType = createIndexType(type, /*stringsOnly*/ false)); } + function getNumericLiteralValue(node: NumericLiteral): number | PseudoBigInt { + if (node.numericLiteralFlags & TokenFlags.BigInt) { + return { negative: false, base10Value: parsePseudoBigInt(node.text) }; + } + return +node.text; + } + + function getNumericLiteralType(node: NumericLiteral): LiteralType { + return getLiteralType(getNumericLiteralValue(node)); + } + function getLiteralTypeFromPropertyName(prop: Symbol, include: TypeFlags) { if (!(getDeclarationModifierFlagsFromSymbol(prop) & ModifierFlags.NonPublicAccessibilityModifier)) { let type = getLateBoundSymbol(prop).nameType; if (!type && !isKnownSymbol(prop)) { const name = prop.valueDeclaration && getNameOfDeclaration(prop.valueDeclaration); - type = name && isNumericLiteral(name) ? getLiteralType(+name.text) : - name && name.kind === SyntaxKind.ComputedPropertyName && isNumericLiteral(name.expression) ? getLiteralType(+name.expression.text) : + type = name && isNumericLiteral(name) ? getNumericLiteralType(name) : + name && name.kind === SyntaxKind.ComputedPropertyName && isNumericLiteral(name.expression) ? getNumericLiteralType(name.expression) : getLiteralType(symbolName(prop)); } if (type && type.flags & include) { @@ -9860,7 +9907,7 @@ namespace ts { if (right.flags & TypeFlags.Union) { return mapType(right, t => getSpreadType(left, t, symbol, typeFlags, objectFlags)); } - if (right.flags & (TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive | TypeFlags.Index)) { + if (right.flags & (TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive | TypeFlags.Index)) { return left; } @@ -9968,7 +10015,7 @@ namespace ts { return index; } - function createLiteralType(flags: TypeFlags, value: string | number, symbol: Symbol | undefined) { + function createLiteralType(flags: TypeFlags, value: string | number | PseudoBigInt, symbol: Symbol | undefined) { const type = createType(flags); type.symbol = symbol!; type.value = value; @@ -9993,16 +10040,18 @@ namespace ts { type; } - function getLiteralType(value: string | number, enumId?: number, symbol?: Symbol) { + function getLiteralType(value: string | number | PseudoBigInt, enumId?: number, symbol?: Symbol) { // We store all literal types in a single map with keys of the form '#NNN' and '@SSS', // where NNN is the text representation of a numeric literal and SSS are the characters // of a string literal. For literal enum members we use 'EEE#NNN' and 'EEE@SSS', where // EEE is a unique id for the containing enum type. - const qualifier = typeof value === "number" ? "#" : "@"; - const key = enumId ? enumId + qualifier + value : qualifier + value; + const qualifier = typeof value === "number" ? "#" : typeof value === "string" ? "@" : "n"; + const key = (enumId ? enumId : "") + qualifier + (typeof value === "object" ? pseudoBigIntToString(value) : value); let type = literalTypes.get(key); if (!type) { - const flags = (typeof value === "number" ? TypeFlags.NumberLiteral : TypeFlags.StringLiteral) | (enumId ? TypeFlags.EnumLiteral : 0); + const flags = (typeof value === "number" ? TypeFlags.NumberLiteral : + typeof value === "string" ? TypeFlags.StringLiteral : TypeFlags.BigIntLiteral) | + (enumId ? TypeFlags.EnumLiteral : 0); literalTypes.set(key, type = createLiteralType(flags, value, symbol)); } return type; @@ -10064,6 +10113,8 @@ namespace ts { return stringType; case SyntaxKind.NumberKeyword: return numberType; + case SyntaxKind.BigIntKeyword: + return bigintType; case SyntaxKind.BooleanKeyword: return booleanType; case SyntaxKind.SymbolKeyword: @@ -11247,6 +11298,7 @@ namespace ts { if (s & TypeFlags.NumberLiteral && s & TypeFlags.EnumLiteral && t & TypeFlags.NumberLiteral && !(t & TypeFlags.EnumLiteral) && (source).value === (target).value) return true; + if (s & TypeFlags.BigIntLike && t & TypeFlags.BigInt) return true; if (s & TypeFlags.BooleanLike && t & TypeFlags.Boolean) return true; if (s & TypeFlags.ESSymbolLike && t & TypeFlags.ESSymbol) return true; if (s & TypeFlags.Enum && t & TypeFlags.Enum && isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter)) return true; @@ -13036,6 +13088,7 @@ namespace ts { return type.flags & TypeFlags.EnumLiteral ? getBaseTypeOfEnumLiteralType(type) : type.flags & TypeFlags.StringLiteral ? stringType : type.flags & TypeFlags.NumberLiteral ? numberType : + type.flags & TypeFlags.BigIntLiteral ? bigintType : type.flags & TypeFlags.BooleanLiteral ? booleanType : type.flags & TypeFlags.Union ? getUnionType(sameMap((type).types, getBaseTypeOfLiteralType)) : type; @@ -13045,6 +13098,7 @@ namespace ts { return type.flags & TypeFlags.EnumLiteral && type.flags & TypeFlags.FreshLiteral ? getBaseTypeOfEnumLiteralType(type) : type.flags & TypeFlags.StringLiteral && type.flags & TypeFlags.FreshLiteral ? stringType : type.flags & TypeFlags.NumberLiteral && type.flags & TypeFlags.FreshLiteral ? numberType : + type.flags & TypeFlags.BigIntLiteral && type.flags & TypeFlags.FreshLiteral ? bigintType : type.flags & TypeFlags.BooleanLiteral && type.flags & TypeFlags.FreshLiteral ? booleanType : type.flags & TypeFlags.Union ? getUnionType(sameMap((type).types, getWidenedLiteralType)) : type; @@ -13084,6 +13138,10 @@ namespace ts { return getTypeReferenceArity(type) - (type.target.hasRestElement ? 1 : 0); } + function isZeroBigInt({value}: BigIntLiteralType) { + return value.base10Value === "0"; + } + function getFalsyFlagsOfTypes(types: Type[]): TypeFlags { let result: TypeFlags = 0; for (const t of types) { @@ -13099,6 +13157,7 @@ namespace ts { return type.flags & TypeFlags.Union ? getFalsyFlagsOfTypes((type).types) : type.flags & TypeFlags.StringLiteral ? (type).value === "" ? TypeFlags.StringLiteral : 0 : type.flags & TypeFlags.NumberLiteral ? (type).value === 0 ? TypeFlags.NumberLiteral : 0 : + type.flags & TypeFlags.BigIntLiteral ? isZeroBigInt(type) ? TypeFlags.BigIntLiteral : 0 : type.flags & TypeFlags.BooleanLiteral ? (type === falseType || type === regularFalseType) ? TypeFlags.BooleanLiteral : 0 : type.flags & TypeFlags.PossiblyFalsy; } @@ -13116,11 +13175,13 @@ namespace ts { function getDefinitelyFalsyPartOfType(type: Type): Type { return type.flags & TypeFlags.String ? emptyStringType : type.flags & TypeFlags.Number ? zeroType : + type.flags & TypeFlags.BigInt ? zeroBigIntType : type === regularFalseType || type === falseType || type.flags & (TypeFlags.Void | TypeFlags.Undefined | TypeFlags.Null) || type.flags & TypeFlags.StringLiteral && (type).value === "" || - type.flags & TypeFlags.NumberLiteral && (type).value === 0 ? type : + type.flags & TypeFlags.NumberLiteral && (type).value === 0 || + type.flags & TypeFlags.BigIntLiteral && isZeroBigInt(type) ? type : neverType; } @@ -14498,8 +14559,17 @@ namespace ts { if (flags & TypeFlags.NumberLiteral) { const isZero = (type).value === 0; return strictNullChecks ? - isZero ? TypeFacts.ZeroStrictFacts : TypeFacts.NonZeroStrictFacts : - isZero ? TypeFacts.ZeroFacts : TypeFacts.NonZeroFacts; + isZero ? TypeFacts.ZeroNumberStrictFacts : TypeFacts.NonZeroNumberStrictFacts : + isZero ? TypeFacts.ZeroNumberFacts : TypeFacts.NonZeroNumberFacts; + } + if (flags & TypeFlags.BigInt) { + return strictNullChecks ? TypeFacts.BigIntStrictFacts : TypeFacts.BigIntFacts; + } + if (flags & TypeFlags.BigIntLiteral) { + const isZero = isZeroBigInt(type); + return strictNullChecks ? + isZero ? TypeFacts.ZeroBigIntStrictFacts : TypeFacts.NonZeroBigIntStrictFacts : + isZero ? TypeFacts.ZeroBigIntFacts : TypeFacts.NonZeroBigIntFacts; } if (flags & TypeFlags.Boolean) { return strictNullChecks ? TypeFacts.BooleanStrictFacts : TypeFacts.BooleanFacts; @@ -14810,10 +14880,12 @@ namespace ts { // literals in typeWithLiterals, respectively. function replacePrimitivesWithLiterals(typeWithPrimitives: Type, typeWithLiterals: Type) { if (isTypeSubsetOf(stringType, typeWithPrimitives) && maybeTypeOfKind(typeWithLiterals, TypeFlags.StringLiteral) || - isTypeSubsetOf(numberType, typeWithPrimitives) && maybeTypeOfKind(typeWithLiterals, TypeFlags.NumberLiteral)) { + isTypeSubsetOf(numberType, typeWithPrimitives) && maybeTypeOfKind(typeWithLiterals, TypeFlags.NumberLiteral) || + isTypeSubsetOf(bigintType, typeWithPrimitives) && maybeTypeOfKind(typeWithLiterals, TypeFlags.BigIntLiteral)) { return mapType(typeWithPrimitives, t => t.flags & TypeFlags.String ? extractTypesOfKind(typeWithLiterals, TypeFlags.String | TypeFlags.StringLiteral) : t.flags & TypeFlags.Number ? extractTypesOfKind(typeWithLiterals, TypeFlags.Number | TypeFlags.NumberLiteral) : + t.flags & TypeFlags.BigInt ? extractTypesOfKind(typeWithLiterals, TypeFlags.BigInt | TypeFlags.BigIntLiteral) : t); } return typeWithPrimitives; @@ -21282,7 +21354,7 @@ namespace ts { } function checkArithmeticOperandType(operand: Node, type: Type, diagnostic: DiagnosticMessage): boolean { - if (!isTypeAssignableToKind(type, TypeFlags.NumberLike)) { + if (!isTypeAssignableTo(type, numberOrBigIntType)) { error(operand, diagnostic); return false; } @@ -21430,10 +21502,19 @@ namespace ts { } if (node.operand.kind === SyntaxKind.NumericLiteral) { if (node.operator === SyntaxKind.MinusToken) { - return getFreshTypeOfLiteralType(getLiteralType(-(node.operand).text)); + const value = getNumericLiteralValue(node.operand as NumericLiteral); + return getFreshTypeOfLiteralType(getLiteralType( + // Keep number as number, bigint as bigint + typeof value === "number" + ? -value + : { negative: !value.negative, base10Value: value.base10Value } + )); } else if (node.operator === SyntaxKind.PlusToken) { - return getFreshTypeOfLiteralType(getLiteralType(+(node.operand).text)); + if (isTypeAssignableToKind(operandType, TypeFlags.BigIntLike)) { + error(node.operand, Diagnostics.Operator_0_cannot_be_applied_to_type_1, tokenToString(node.operator), typeToString(operandType)); + } + return getFreshTypeOfLiteralType(getNumericLiteralType(node.operand as NumericLiteral)); } } switch (node.operator) { @@ -21444,7 +21525,13 @@ namespace ts { if (maybeTypeOfKind(operandType, TypeFlags.ESSymbolLike)) { error(node.operand, Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, tokenToString(node.operator)); } - return numberType; + if (node.operator === SyntaxKind.PlusToken) { + if (maybeTypeOfKind(operandType, TypeFlags.BigIntLike)) { + error(node.operand, Diagnostics.Operator_0_cannot_be_applied_to_type_1, tokenToString(node.operator), typeToString(operandType)); + } + return numberType; + } + return getUnaryResultType(operandType); case SyntaxKind.ExclamationToken: checkTruthinessExpression(node.operand); const facts = getTypeFacts(operandType) & (TypeFacts.Truthy | TypeFacts.Falsy); @@ -21459,7 +21546,7 @@ namespace ts { // run check only if former checks succeeded to avoid reporting cascading errors checkReferenceExpression(node.operand, Diagnostics.The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access); } - return numberType; + return getUnaryResultType(operandType); } return errorType; } @@ -21477,6 +21564,16 @@ namespace ts { // run check only if former checks succeeded to avoid reporting cascading errors checkReferenceExpression(node.operand, Diagnostics.The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access); } + return getUnaryResultType(operandType); + } + + function getUnaryResultType(operandType: Type): Type { + if (maybeTypeOfKind(operandType, TypeFlags.BigIntLike)) { + return isTypeAssignableToKind(operandType, TypeFlags.AnyOrUnknown) || maybeTypeOfKind(operandType, TypeFlags.NumberLike) + ? numberOrBigIntType + : bigintType; + } + // If it's not a bigint type, implicit coercion will result in a number return numberType; } @@ -21505,6 +21602,7 @@ namespace ts { return false; } return !!(kind & TypeFlags.NumberLike) && isTypeAssignableTo(source, numberType) || + !!(kind & TypeFlags.BigIntLike) && isTypeAssignableTo(source, bigintType) || !!(kind & TypeFlags.StringLike) && isTypeAssignableTo(source, stringType) || !!(kind & TypeFlags.BooleanLike) && isTypeAssignableTo(source, booleanType) || !!(kind & TypeFlags.Void) && isTypeAssignableTo(source, voidType) || @@ -21869,17 +21967,39 @@ namespace ts { (rightType.flags & TypeFlags.BooleanLike) && (suggestedOperator = getSuggestedBooleanOperator(operatorToken.kind)) !== undefined) { error(errorNode || operatorToken, Diagnostics.The_0_operator_is_not_allowed_for_boolean_types_Consider_using_1_instead, tokenToString(operatorToken.kind), tokenToString(suggestedOperator)); + return numberType; } else { // otherwise just check each operand separately and report errors as normal const leftOk = checkArithmeticOperandType(left, leftType, Diagnostics.The_left_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_bigint_or_an_enum_type); const rightOk = checkArithmeticOperandType(right, rightType, Diagnostics.The_right_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_bigint_or_an_enum_type); - if (leftOk && rightOk) { - checkAssignmentOperator(numberType); + let resultType: Type; + // If both are any or unknown, allow operation; assume it will resolve to number + if ((isTypeAssignableToKind(leftType, TypeFlags.AnyOrUnknown) && isTypeAssignableToKind(rightType, TypeFlags.AnyOrUnknown)) || + // Or, if neither could be bigint, implicit coercion results in a number result + !(maybeTypeOfKind(leftType, TypeFlags.BigIntLike) || maybeTypeOfKind(rightType, TypeFlags.BigIntLike)) + ) { + resultType = numberType; } + // At least one is assignable to bigint, so both should be only assignable to bigint + else if (isTypeAssignableToKind(leftType, TypeFlags.BigIntLike) && isTypeAssignableToKind(rightType, TypeFlags.BigIntLike)) { + switch (operator) { + case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: + reportOperatorError(); + } + resultType = bigintType; + } + else { + reportOperatorError(); + resultType = errorType; + } + if (leftOk && rightOk) { + checkAssignmentOperator(resultType); + } + return resultType; } - return numberType; case SyntaxKind.PlusToken: case SyntaxKind.PlusEqualsToken: if (leftType === silentNeverType || rightType === silentNeverType) { @@ -21897,6 +22017,10 @@ namespace ts { // If both operands are of the Number primitive type, the result is of the Number primitive type. resultType = numberType; } + else if (isTypeAssignableToKind(leftType, TypeFlags.BigIntLike, /*strict*/ true) && isTypeAssignableToKind(rightType, TypeFlags.BigIntLike, /*strict*/ true)) { + // If both operands are of the BigInt primitive type, the result is of the BigInt primitive type. + resultType = bigintType; + } else if (isTypeAssignableToKind(leftType, TypeFlags.StringLike, /*strict*/ true) || isTypeAssignableToKind(rightType, TypeFlags.StringLike, /*strict*/ true)) { // If one or both operands are of the String primitive type, the result is of the String primitive type. resultType = stringType; @@ -21928,7 +22052,9 @@ namespace ts { if (checkForDisallowedESSymbolOperand(operator)) { leftType = getBaseTypeOfLiteralType(checkNonNullType(leftType, left)); rightType = getBaseTypeOfLiteralType(checkNonNullType(rightType, right)); - if (!isTypeComparableTo(leftType, rightType) && !isTypeComparableTo(rightType, leftType)) { + if (!(isTypeComparableTo(leftType, rightType) || isTypeComparableTo(rightType, leftType) || + (isTypeAssignableTo(leftType, numberOrBigIntType) && isTypeAssignableTo(rightType, numberOrBigIntType)) + )) { reportOperatorError(); } } @@ -22259,6 +22385,7 @@ namespace ts { const constraint = getBaseConstraintOfType(contextualType) || emptyObjectType; return maybeTypeOfKind(constraint, TypeFlags.String) && maybeTypeOfKind(candidateType, TypeFlags.StringLiteral) || maybeTypeOfKind(constraint, TypeFlags.Number) && maybeTypeOfKind(candidateType, TypeFlags.NumberLiteral) || + maybeTypeOfKind(constraint, TypeFlags.BigInt) && maybeTypeOfKind(candidateType, TypeFlags.BigIntLiteral) || maybeTypeOfKind(constraint, TypeFlags.ESSymbol) && maybeTypeOfKind(candidateType, TypeFlags.UniqueESSymbol) || isLiteralOfContextualType(candidateType, constraint); } @@ -22266,6 +22393,7 @@ namespace ts { // literal context for all literals of that primitive type. return !!(contextualType.flags & (TypeFlags.StringLiteral | TypeFlags.Index) && maybeTypeOfKind(candidateType, TypeFlags.StringLiteral) || contextualType.flags & TypeFlags.NumberLiteral && maybeTypeOfKind(candidateType, TypeFlags.NumberLiteral) || + contextualType.flags & TypeFlags.BigIntLiteral && maybeTypeOfKind(candidateType, TypeFlags.BigIntLiteral) || contextualType.flags & TypeFlags.BooleanLiteral && maybeTypeOfKind(candidateType, TypeFlags.BooleanLiteral) || contextualType.flags & TypeFlags.UniqueESSymbol && maybeTypeOfKind(candidateType, TypeFlags.UniqueESSymbol)); } @@ -22427,7 +22555,7 @@ namespace ts { return getFreshTypeOfLiteralType(getLiteralType((node as StringLiteralLike).text)); case SyntaxKind.NumericLiteral: checkGrammarNumericLiteral(node as NumericLiteral); - return getFreshTypeOfLiteralType(getLiteralType(+(node as NumericLiteral).text)); + return getFreshTypeOfLiteralType(getNumericLiteralType(node as NumericLiteral)); case SyntaxKind.TrueKeyword: return trueType; case SyntaxKind.FalseKeyword: @@ -25835,6 +25963,7 @@ namespace ts { case "any": case "unknown": case "number": + case "bigint": case "boolean": case "string": case "symbol": @@ -26463,7 +26592,8 @@ namespace ts { return (expr).text; case SyntaxKind.NumericLiteral: checkGrammarNumericLiteral(expr); - return +(expr).text; + const literalValue = getNumericLiteralValue(expr); + return typeof literalValue === "number" ? literalValue : undefined; // don't evaluate bigint case SyntaxKind.ParenthesizedExpression: return evaluate((expr).expression); case SyntaxKind.Identifier: @@ -28517,6 +28647,9 @@ namespace ts { else if (isTypeAssignableToKind(type, TypeFlags.NumberLike)) { return TypeReferenceSerializationKind.NumberLikeType; } + else if (isTypeAssignableToKind(type, TypeFlags.BigIntLike)) { + return TypeReferenceSerializationKind.BigIntLikeType; + } else if (isTypeAssignableToKind(type, TypeFlags.StringLike)) { return TypeReferenceSerializationKind.StringLikeType; } diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 01de5850471..39d3d5c3c83 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -68,13 +68,18 @@ 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 + const literal = createNumericLiteral(pseudoBigIntToString(value) + "n"); + literal.numericLiteralFlags |= TokenFlags.BigInt; + return literal; + } if (typeof value === "boolean") { return value ? createTrue() : createFalse(); } diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index a5ab1e8475f..057dfc97a74 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -2006,6 +2006,9 @@ namespace ts { case TypeReferenceSerializationKind.VoidNullableOrNeverType: return createVoidZero(); + case TypeReferenceSerializationKind.BigIntLikeType: + return createIdentifier("BigInt"); + case TypeReferenceSerializationKind.BooleanType: return createIdentifier("Boolean"); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 4a25a9f9eef..d926c56dc1d 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -271,6 +271,7 @@ namespace ts { UnknownKeyword, FromKeyword, GlobalKeyword, + BigIntKeyword, OfKeyword, // LastKeyword and LastToken and LastContextualKeyword // Parse tree nodes @@ -1109,6 +1110,7 @@ namespace ts { kind: SyntaxKind.AnyKeyword | SyntaxKind.UnknownKeyword | SyntaxKind.NumberKeyword + | SyntaxKind.BigIntKeyword | SyntaxKind.ObjectKeyword | SyntaxKind.BooleanKeyword | SyntaxKind.StringKeyword @@ -1658,8 +1660,9 @@ namespace ts { BinarySpecifier = 1 << 7, // e.g. `0b0110010000000000` OctalSpecifier = 1 << 8, // e.g. `0o777` ContainsSeparator = 1 << 9, // e.g. `0b1100_0101` + BigInt = 1 << 10, // e.g. `123n` BinaryOrOctalSpecifier = BinarySpecifier | OctalSpecifier, - NumericLiteralFlags = Scientific | Octal | HexSpecifier | BinarySpecifier | OctalSpecifier | ContainsSeparator + NumericLiteralFlags = Scientific | Octal | HexSpecifier | BinaryOrOctalSpecifier | ContainsSeparator | BigInt } export interface NumericLiteral extends LiteralExpression { @@ -3461,6 +3464,7 @@ namespace ts { // of a type, such as the global `Promise` type in lib.d.ts). VoidNullableOrNeverType, // The TypeReferenceNode resolves to a Void-like, Nullable, or Never type. NumberLikeType, // The TypeReferenceNode resolves to a Number-like type. + BigIntLikeType, // The TypeReferenceNode resolves to a BigInt-like type. StringLikeType, // The TypeReferenceNode resolves to a String-like type. BooleanType, // The TypeReferenceNode resolves to a Boolean-like type. ArrayLikeType, // The TypeReferenceNode resolves to an Array-like type. @@ -3805,60 +3809,63 @@ namespace ts { Number = 1 << 3, Boolean = 1 << 4, Enum = 1 << 5, - StringLiteral = 1 << 6, - NumberLiteral = 1 << 7, - BooleanLiteral = 1 << 8, - EnumLiteral = 1 << 9, // Always combined with StringLiteral, NumberLiteral, or Union - ESSymbol = 1 << 10, // Type of symbol primitive introduced in ES6 - UniqueESSymbol = 1 << 11, // unique symbol - Void = 1 << 12, - Undefined = 1 << 13, - Null = 1 << 14, - Never = 1 << 15, // Never type - TypeParameter = 1 << 16, // Type parameter - Object = 1 << 17, // Object type - Union = 1 << 18, // Union (T | U) - Intersection = 1 << 19, // Intersection (T & U) - Index = 1 << 20, // keyof T - IndexedAccess = 1 << 21, // T[K] - Conditional = 1 << 22, // T extends U ? X : Y - Substitution = 1 << 23, // Type parameter substitution - NonPrimitive = 1 << 24, // intrinsic object type + BigInt = 1 << 6, + StringLiteral = 1 << 7, + NumberLiteral = 1 << 8, + BooleanLiteral = 1 << 9, + EnumLiteral = 1 << 10, // Always combined with StringLiteral, NumberLiteral, or Union + BigIntLiteral = 1 << 11, + ESSymbol = 1 << 12, // Type of symbol primitive introduced in ES6 + UniqueESSymbol = 1 << 13, // unique symbol + Void = 1 << 14, + Undefined = 1 << 15, + Null = 1 << 16, + Never = 1 << 17, // Never type + TypeParameter = 1 << 18, // Type parameter + Object = 1 << 19, // Object type + Union = 1 << 20, // Union (T | U) + Intersection = 1 << 21, // Intersection (T & U) + Index = 1 << 22, // keyof T + IndexedAccess = 1 << 23, // T[K] + Conditional = 1 << 24, // T extends U ? X : Y + Substitution = 1 << 25, // Type parameter substitution + NonPrimitive = 1 << 26, // intrinsic object type /* @internal */ - FreshLiteral = 1 << 25, // Fresh literal or unique type + FreshLiteral = 1 << 27, // Fresh literal or unique type /* @internal */ - UnionOfPrimitiveTypes = 1 << 26, // Type is union of primitive types + UnionOfPrimitiveTypes = 1 << 28, // Type is union of primitive types /* @internal */ - ContainsWideningType = 1 << 27, // Type is or contains undefined or null widening type + ContainsWideningType = 1 << 29, // Type is or contains undefined or null widening type /* @internal */ - ContainsObjectLiteral = 1 << 28, // Type is or contains object literal type + ContainsObjectLiteral = 1 << 30, // Type is or contains object literal type /* @internal */ - ContainsAnyFunctionType = 1 << 29, // Type is or contains the anyFunctionType + ContainsAnyFunctionType = 1 << 31, // Type is or contains the anyFunctionType /* @internal */ AnyOrUnknown = Any | Unknown, /* @internal */ Nullable = Undefined | Null, - Literal = StringLiteral | NumberLiteral | BooleanLiteral, + Literal = StringLiteral | NumberLiteral | BigIntLiteral | BooleanLiteral, Unit = Literal | UniqueESSymbol | Nullable, StringOrNumberLiteral = StringLiteral | NumberLiteral, /* @internal */ StringOrNumberLiteralOrUnique = StringLiteral | NumberLiteral | UniqueESSymbol, /* @internal */ - DefinitelyFalsy = StringLiteral | NumberLiteral | BooleanLiteral | Void | Undefined | Null, - PossiblyFalsy = DefinitelyFalsy | String | Number | Boolean, + DefinitelyFalsy = StringLiteral | NumberLiteral | BigIntLiteral | BooleanLiteral | Void | Undefined | Null, + PossiblyFalsy = DefinitelyFalsy | String | Number | BigInt | Boolean, /* @internal */ - Intrinsic = Any | Unknown | String | Number | Boolean | BooleanLiteral | ESSymbol | Void | Undefined | Null | Never | NonPrimitive, + Intrinsic = Any | Unknown | String | Number | BigInt | Boolean | BooleanLiteral | ESSymbol | Void | Undefined | Null | Never | NonPrimitive, /* @internal */ - Primitive = String | Number | Boolean | Enum | EnumLiteral | ESSymbol | Void | Undefined | Null | Literal | UniqueESSymbol, + Primitive = String | Number | BigInt | Boolean | Enum | EnumLiteral | ESSymbol | Void | Undefined | Null | Literal | UniqueESSymbol, StringLike = String | StringLiteral, NumberLike = Number | NumberLiteral | Enum, + BigIntLike = BigInt | BigIntLiteral, BooleanLike = Boolean | BooleanLiteral, EnumLike = Enum | EnumLiteral, ESSymbolLike = ESSymbol | UniqueESSymbol, VoidLike = Void | Undefined, /* @internal */ - DisjointDomains = NonPrimitive | StringLike | NumberLike | BooleanLike | ESSymbolLike | VoidLike | Null, + DisjointDomains = NonPrimitive | StringLike | NumberLike | BigIntLike | BooleanLike | ESSymbolLike | VoidLike | Null, UnionOrIntersection = Union | Intersection, StructuredType = Object | Union | Intersection, TypeVariable = TypeParameter | IndexedAccess, @@ -3869,7 +3876,7 @@ namespace ts { // 'Narrowable' types are types where narrowing actually narrows. // This *should* be every type other than null, undefined, void, and never - Narrowable = Any | Unknown | StructuredOrInstantiable | StringLike | NumberLike | BooleanLike | ESSymbol | UniqueESSymbol | NonPrimitive, + Narrowable = Any | Unknown | StructuredOrInstantiable | StringLike | NumberLike | BigIntLike | BooleanLike | ESSymbol | UniqueESSymbol | NonPrimitive, NotUnionOrUnit = Any | Unknown | ESSymbol | Object | NonPrimitive, /* @internal */ NotPrimitiveUnion = Any | Unknown | Enum | Void | Never | StructuredOrInstantiable, @@ -3926,10 +3933,11 @@ namespace ts { // String literal types (TypeFlags.StringLiteral) // Numeric literal types (TypeFlags.NumberLiteral) + // BigInt literal types (TypeFlags.BigIntLiteral) export interface LiteralType extends Type { - value: string | number; // Value of literal - freshType: LiteralType; // Fresh version of type - regularType: LiteralType; // Regular version of type + value: string | number | PseudoBigInt; // Value of literal + freshType: LiteralType; // Fresh version of type + regularType: LiteralType; // Regular version of type } // Unique symbol types (TypeFlags.UniqueESSymbol) @@ -3945,6 +3953,10 @@ namespace ts { value: number; } + export interface BigIntLiteralType extends LiteralType { + value: PseudoBigInt; + } + // Enum types (TypeFlags.Enum) export interface EnumType extends Type { } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 34d80992153..87795492a11 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -976,6 +976,7 @@ namespace ts { case SyntaxKind.AnyKeyword: case SyntaxKind.UnknownKeyword: case SyntaxKind.NumberKeyword: + case SyntaxKind.BigIntKeyword: case SyntaxKind.StringKeyword: case SyntaxKind.BooleanKeyword: case SyntaxKind.SymbolKeyword: @@ -6214,6 +6215,7 @@ namespace ts { || kind === SyntaxKind.AnyKeyword || kind === SyntaxKind.UnknownKeyword || kind === SyntaxKind.NumberKeyword + || kind === SyntaxKind.BigIntKeyword || kind === SyntaxKind.ObjectKeyword || kind === SyntaxKind.BooleanKeyword || kind === SyntaxKind.StringKeyword diff --git a/src/services/completions.ts b/src/services/completions.ts index c7d888b647e..90c005d2131 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -165,8 +165,9 @@ namespace ts.Completions { }); } - const completionNameForLiteral = JSON.stringify; - function createCompletionEntryForLiteral(literal: string | number): CompletionEntry { + const completionNameForLiteral = (literal: string | number | PseudoBigInt) => + typeof literal === "object" ? pseudoBigIntToString(literal) + "n" : JSON.stringify(literal); + function createCompletionEntryForLiteral(literal: string | number | PseudoBigInt): CompletionEntry { return { name: completionNameForLiteral(literal), kind: ScriptElementKind.string, kindModifiers: ScriptElementKindModifier.none, sortText: "0" }; } @@ -337,7 +338,7 @@ namespace ts.Completions { readonly isJsxInitializer: IsJsxInitializer; } function getSymbolCompletionFromEntryId(program: Program, log: Log, sourceFile: SourceFile, position: number, entryId: CompletionEntryIdentifier, - ): SymbolCompletion | { type: "request", request: Request } | { type: "literal", literal: string | number } | { type: "none" } { + ): SymbolCompletion | { type: "request", request: Request } | { type: "literal", literal: string | number | PseudoBigInt } | { type: "none" } { const compilerOptions = program.getCompilerOptions(); const completionData = getCompletionData(program, log, sourceFile, isUncheckedFile(sourceFile, compilerOptions), position, { includeCompletionsForModuleExports: true, includeCompletionsWithInsertText: true }, entryId); if (!completionData) { @@ -502,7 +503,7 @@ namespace ts.Completions { readonly isNewIdentifierLocation: boolean; readonly location: Node | undefined; readonly keywordFilters: KeywordCompletionFilters; - readonly literals: ReadonlyArray; + readonly literals: ReadonlyArray; readonly symbolToOriginInfoMap: SymbolOriginInfoMap; readonly recommendedCompletion: Symbol | undefined; readonly previousToken: Node | undefined;