Skip to content

Commit dfb8701

Browse files
authored
fix35982: allow BigIntLiteral to parse as PropertyName for literal object and indices (#58608)
1 parent 85d6bb6 commit dfb8701

22 files changed

+1057
-126
lines changed

Diff for: src/compiler/checker.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -18772,14 +18772,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1877218772
}
1877318773
if (accessNode) {
1877418774
const indexNode = getIndexNodeForAccessExpression(accessNode);
18775-
if (indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) {
18775+
if (indexNode.kind !== SyntaxKind.BigIntLiteral && indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) {
1877618776
error(indexNode, Diagnostics.Property_0_does_not_exist_on_type_1, "" + (indexType as StringLiteralType | NumberLiteralType).value, typeToString(objectType));
1877718777
}
1877818778
else if (indexType.flags & (TypeFlags.String | TypeFlags.Number)) {
1877918779
error(indexNode, Diagnostics.Type_0_has_no_matching_index_signature_for_type_1, typeToString(objectType), typeToString(indexType));
1878018780
}
1878118781
else {
18782-
error(indexNode, Diagnostics.Type_0_cannot_be_used_as_an_index_type, typeToString(indexType));
18782+
const typeString = indexNode.kind === SyntaxKind.BigIntLiteral ? "bigint" : typeToString(indexType);
18783+
error(indexNode, Diagnostics.Type_0_cannot_be_used_as_an_index_type, typeString);
1878318784
}
1878418785
}
1878518786
if (isTypeAny(indexType)) {
@@ -43908,6 +43909,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4390843909
return;
4390943910
}
4391043911

43912+
if (node.name.kind === SyntaxKind.BigIntLiteral) {
43913+
error(node.name, Diagnostics.A_bigint_literal_cannot_be_used_as_a_property_name);
43914+
}
43915+
4391143916
const type = convertAutoToAny(getTypeOfSymbol(symbol));
4391243917
if (node === symbol.valueDeclaration) {
4391343918
// Node is the primary declaration of the symbol, just validate the initializer
@@ -51114,6 +51119,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
5111451119
if (name.kind === SyntaxKind.NumericLiteral) {
5111551120
checkGrammarNumericLiteral(name);
5111651121
}
51122+
if (name.kind === SyntaxKind.BigIntLiteral) {
51123+
addErrorOrSuggestion(/*isError*/ true, createDiagnosticForNode(name, Diagnostics.A_bigint_literal_cannot_be_used_as_a_property_name));
51124+
}
5111751125
currentKind = DeclarationMeaning.PropertyAssignment;
5111851126
break;
5111951127
case SyntaxKind.MethodDeclaration:

Diff for: src/compiler/diagnosticMessages.json

+4
Original file line numberDiff line numberDiff line change
@@ -1809,6 +1809,10 @@
18091809
"category": "Error",
18101810
"code": 1538
18111811
},
1812+
"A 'bigint' literal cannot be used as a property name.": {
1813+
"category": "Error",
1814+
"code": 1539
1815+
},
18121816

18131817
"The types of '{0}' are incompatible between these types.": {
18141818
"category": "Error",

Diff for: src/compiler/parser.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
attachFileToDiagnostics,
1515
AwaitExpression,
1616
BaseNodeFactory,
17+
BigIntLiteral,
1718
BinaryExpression,
1819
BinaryOperatorToken,
1920
BindingElement,
@@ -2692,16 +2693,17 @@ namespace Parser {
26922693
function isLiteralPropertyName(): boolean {
26932694
return tokenIsIdentifierOrKeyword(token()) ||
26942695
token() === SyntaxKind.StringLiteral ||
2695-
token() === SyntaxKind.NumericLiteral;
2696+
token() === SyntaxKind.NumericLiteral ||
2697+
token() === SyntaxKind.BigIntLiteral;
26962698
}
26972699

26982700
function isImportAttributeName(): boolean {
26992701
return tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.StringLiteral;
27002702
}
27012703

27022704
function parsePropertyNameWorker(allowComputedPropertyNames: boolean): PropertyName {
2703-
if (token() === SyntaxKind.StringLiteral || token() === SyntaxKind.NumericLiteral) {
2704-
const node = parseLiteralNode() as StringLiteral | NumericLiteral;
2705+
if (token() === SyntaxKind.StringLiteral || token() === SyntaxKind.NumericLiteral || token() === SyntaxKind.BigIntLiteral) {
2706+
const node = parseLiteralNode() as StringLiteral | NumericLiteral | BigIntLiteral;
27052707
node.text = internIdentifier(node.text);
27062708
return node;
27072709
}
@@ -8058,6 +8060,7 @@ namespace Parser {
80588060
tokenIsIdentifierOrKeyword(token()) ||
80598061
token() === SyntaxKind.StringLiteral ||
80608062
token() === SyntaxKind.NumericLiteral ||
8063+
token() === SyntaxKind.BigIntLiteral ||
80618064
token() === SyntaxKind.AsteriskToken ||
80628065
token() === SyntaxKind.OpenBracketToken
80638066
) {

Diff for: src/compiler/transformers/destructuring.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
isArrayBindingElement,
2424
isArrayBindingOrAssignmentElement,
2525
isArrayBindingOrAssignmentPattern,
26+
isBigIntLiteral,
2627
isBindingElement,
2728
isBindingName,
2829
isBindingOrAssignmentElement,
@@ -558,7 +559,7 @@ function createDestructuringPropertyAccess(flattenContext: FlattenContext, value
558559
const argumentExpression = ensureIdentifier(flattenContext, Debug.checkDefined(visitNode(propertyName.expression, flattenContext.visitor, isExpression)), /*reuseIdentifierExpressions*/ false, /*location*/ propertyName);
559560
return flattenContext.context.factory.createElementAccessExpression(value, argumentExpression);
560561
}
561-
else if (isStringOrNumericLiteralLike(propertyName)) {
562+
else if (isStringOrNumericLiteralLike(propertyName) || isBigIntLiteral(propertyName)) {
562563
const argumentExpression = factory.cloneNode(propertyName);
563564
return flattenContext.context.factory.createElementAccessExpression(value, argumentExpression);
564565
}

Diff for: src/compiler/types.ts

+11-3
Original file line numberDiff line numberDiff line change
@@ -1721,7 +1721,14 @@ export interface QualifiedName extends Node, FlowContainer {
17211721

17221722
export type EntityName = Identifier | QualifiedName;
17231723

1724-
export type PropertyName = Identifier | StringLiteral | NoSubstitutionTemplateLiteral | NumericLiteral | ComputedPropertyName | PrivateIdentifier;
1724+
export type PropertyName =
1725+
| Identifier
1726+
| StringLiteral
1727+
| NoSubstitutionTemplateLiteral
1728+
| NumericLiteral
1729+
| ComputedPropertyName
1730+
| PrivateIdentifier
1731+
| BigIntLiteral;
17251732

17261733
export type MemberName = Identifier | PrivateIdentifier;
17271734

@@ -2340,7 +2347,8 @@ export interface LiteralTypeNode extends TypeNode {
23402347

23412348
export interface StringLiteral extends LiteralExpression, Declaration {
23422349
readonly kind: SyntaxKind.StringLiteral;
2343-
/** @internal */ readonly textSourceNode?: Identifier | StringLiteralLike | NumericLiteral | PrivateIdentifier | JsxNamespacedName; // Allows a StringLiteral to get its text from another node (used by transforms).
2350+
/** @internal */
2351+
readonly textSourceNode?: Identifier | StringLiteralLike | NumericLiteral | PrivateIdentifier | JsxNamespacedName | BigIntLiteral; // Allows a StringLiteral to get its text from another node (used by transforms).
23442352
/**
23452353
* Note: this is only set when synthesizing a node, not during parsing.
23462354
*
@@ -2350,7 +2358,7 @@ export interface StringLiteral extends LiteralExpression, Declaration {
23502358
}
23512359

23522360
export type StringLiteralLike = StringLiteral | NoSubstitutionTemplateLiteral;
2353-
export type PropertyNameLiteral = Identifier | StringLiteralLike | NumericLiteral | JsxNamespacedName;
2361+
export type PropertyNameLiteral = Identifier | StringLiteralLike | NumericLiteral | JsxNamespacedName | BigIntLiteral;
23542362

23552363
export interface TemplateLiteralTypeNode extends TypeNode {
23562364
kind: SyntaxKind.TemplateLiteralType;

Diff for: src/compiler/utilities.ts

+2
Original file line numberDiff line numberDiff line change
@@ -2207,6 +2207,7 @@ export function tryGetTextOfPropertyName(name: PropertyName | NoSubstitutionTemp
22072207
return name.emitNode?.autoGenerate ? undefined : name.escapedText;
22082208
case SyntaxKind.StringLiteral:
22092209
case SyntaxKind.NumericLiteral:
2210+
case SyntaxKind.BigIntLiteral:
22102211
case SyntaxKind.NoSubstitutionTemplateLiteral:
22112212
return escapeLeadingUnderscores(name.text);
22122213
case SyntaxKind.ComputedPropertyName:
@@ -5221,6 +5222,7 @@ export function getPropertyNameForPropertyNameNode(name: PropertyName | JsxAttri
52215222
case SyntaxKind.StringLiteral:
52225223
case SyntaxKind.NoSubstitutionTemplateLiteral:
52235224
case SyntaxKind.NumericLiteral:
5225+
case SyntaxKind.BigIntLiteral:
52245226
return escapeLeadingUnderscores(name.text);
52255227
case SyntaxKind.ComputedPropertyName:
52265228
const nameExpression = name.expression;

Diff for: tests/baselines/reference/api/typescript.d.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -4422,7 +4422,7 @@ declare namespace ts {
44224422
readonly right: Identifier;
44234423
}
44244424
type EntityName = Identifier | QualifiedName;
4425-
type PropertyName = Identifier | StringLiteral | NoSubstitutionTemplateLiteral | NumericLiteral | ComputedPropertyName | PrivateIdentifier;
4425+
type PropertyName = Identifier | StringLiteral | NoSubstitutionTemplateLiteral | NumericLiteral | ComputedPropertyName | PrivateIdentifier | BigIntLiteral;
44264426
type MemberName = Identifier | PrivateIdentifier;
44274427
type DeclarationName = PropertyName | JsxAttributeName | StringLiteralLike | ElementAccessExpression | BindingPattern | EntityNameExpression;
44284428
interface Declaration extends Node {
@@ -4773,7 +4773,7 @@ declare namespace ts {
47734773
readonly kind: SyntaxKind.StringLiteral;
47744774
}
47754775
type StringLiteralLike = StringLiteral | NoSubstitutionTemplateLiteral;
4776-
type PropertyNameLiteral = Identifier | StringLiteralLike | NumericLiteral | JsxNamespacedName;
4776+
type PropertyNameLiteral = Identifier | StringLiteralLike | NumericLiteral | JsxNamespacedName | BigIntLiteral;
47774777
interface TemplateLiteralTypeNode extends TypeNode {
47784778
kind: SyntaxKind.TemplateLiteralType;
47794779
readonly head: TemplateHead;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
badExport.ts(1,10): error TS2304: Cannot find name 'foo'.
2+
badExport.ts(1,17): error TS1003: Identifier expected.
3+
badExport.ts(1,20): error TS1128: Declaration or statement expected.
4+
badExport2.ts(1,10): error TS1003: Identifier expected.
5+
badExport2.ts(1,16): error TS2304: Cannot find name 'foo'.
6+
badExport2.ts(1,20): error TS1128: Declaration or statement expected.
7+
badImport.ts(1,10): error TS1003: Identifier expected.
8+
badImport.ts(1,10): error TS1141: String literal expected.
9+
badImport.ts(1,20): error TS1128: Declaration or statement expected.
10+
badImport.ts(1,22): error TS1434: Unexpected keyword or identifier.
11+
badImport.ts(1,22): error TS2304: Cannot find name 'from'.
12+
badImport2.ts(1,17): error TS1003: Identifier expected.
13+
badImport2.ts(1,17): error TS1141: String literal expected.
14+
badImport2.ts(1,20): error TS1128: Declaration or statement expected.
15+
badImport2.ts(1,22): error TS1434: Unexpected keyword or identifier.
16+
badImport2.ts(1,22): error TS2304: Cannot find name 'from'.
17+
18+
19+
==== foo.ts (0 errors) ====
20+
const foo = 0n;
21+
export { foo as "0n" };
22+
23+
==== correctUse.ts (0 errors) ====
24+
import { "0n" as foo } from "./foo";
25+
export { foo as "0n" };
26+
27+
==== badImport.ts (5 errors) ====
28+
import { 0n as foo } from "./foo";
29+
~~
30+
!!! error TS1003: Identifier expected.
31+
~~~~~~~~~
32+
!!! error TS1141: String literal expected.
33+
~
34+
!!! error TS1128: Declaration or statement expected.
35+
~~~~
36+
!!! error TS1434: Unexpected keyword or identifier.
37+
~~~~
38+
!!! error TS2304: Cannot find name 'from'.
39+
40+
==== badImport2.ts (5 errors) ====
41+
import { foo as 0n } from "./foo";
42+
~~
43+
!!! error TS1003: Identifier expected.
44+
~~
45+
!!! error TS1141: String literal expected.
46+
~
47+
!!! error TS1128: Declaration or statement expected.
48+
~~~~
49+
!!! error TS1434: Unexpected keyword or identifier.
50+
~~~~
51+
!!! error TS2304: Cannot find name 'from'.
52+
53+
==== badExport.ts (3 errors) ====
54+
export { foo as 0n };
55+
~~~
56+
!!! error TS2304: Cannot find name 'foo'.
57+
~~
58+
!!! error TS1003: Identifier expected.
59+
~
60+
!!! error TS1128: Declaration or statement expected.
61+
62+
==== badExport2.ts (3 errors) ====
63+
export { 0n as foo };
64+
~~
65+
!!! error TS1003: Identifier expected.
66+
~~~
67+
!!! error TS2304: Cannot find name 'foo'.
68+
~
69+
!!! error TS1128: Declaration or statement expected.
+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//// [tests/cases/compiler/bigintArbirtraryIdentifier.ts] ////
2+
3+
//// [foo.ts]
4+
const foo = 0n;
5+
export { foo as "0n" };
6+
7+
//// [correctUse.ts]
8+
import { "0n" as foo } from "./foo";
9+
export { foo as "0n" };
10+
11+
//// [badImport.ts]
12+
import { 0n as foo } from "./foo";
13+
14+
//// [badImport2.ts]
15+
import { foo as 0n } from "./foo";
16+
17+
//// [badExport.ts]
18+
export { foo as 0n };
19+
20+
//// [badExport2.ts]
21+
export { 0n as foo };
22+
23+
//// [foo.js]
24+
const foo = 0n;
25+
export { foo as "0n" };
26+
//// [correctUse.js]
27+
import { "0n" as foo } from "./foo";
28+
export { foo as "0n" };
29+
//// [badImport.js]
30+
from;
31+
"./foo";
32+
export {};
33+
//// [badImport2.js]
34+
from;
35+
"./foo";
36+
export {};
37+
//// [badExport.js]
38+
export { foo as };
39+
0n;
40+
;
41+
//// [badExport2.js]
42+
0n;
43+
;
44+
export {};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//// [tests/cases/compiler/bigintArbirtraryIdentifier.ts] ////
2+
3+
=== foo.ts ===
4+
const foo = 0n;
5+
>foo : Symbol(foo, Decl(foo.ts, 0, 5))
6+
7+
export { foo as "0n" };
8+
>foo : Symbol(foo, Decl(foo.ts, 0, 5))
9+
>"0n" : Symbol("0n", Decl(foo.ts, 1, 8))
10+
11+
=== correctUse.ts ===
12+
import { "0n" as foo } from "./foo";
13+
>foo : Symbol(foo, Decl(correctUse.ts, 0, 8))
14+
15+
export { foo as "0n" };
16+
>foo : Symbol(foo, Decl(correctUse.ts, 0, 8))
17+
>"0n" : Symbol("0n", Decl(correctUse.ts, 1, 8))
18+
19+
=== badImport.ts ===
20+
import { 0n as foo } from "./foo";
21+
>foo : Symbol(foo)
22+
23+
=== badImport2.ts ===
24+
import { foo as 0n } from "./foo";
25+
> : Symbol((Missing), Decl(badImport2.ts, 0, 8))
26+
27+
=== badExport.ts ===
28+
export { foo as 0n };
29+
> : Symbol((Missing), Decl(badExport.ts, 0, 8))
30+
31+
=== badExport2.ts ===
32+
export { 0n as foo };
33+
>foo : Symbol(foo)
34+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//// [tests/cases/compiler/bigintArbirtraryIdentifier.ts] ////
2+
3+
=== foo.ts ===
4+
const foo = 0n;
5+
>foo : 0n
6+
> : ^^
7+
>0n : 0n
8+
> : ^^
9+
10+
export { foo as "0n" };
11+
>foo : 0n
12+
> : ^^
13+
>"0n" : 0n
14+
> : ^^
15+
16+
=== correctUse.ts ===
17+
import { "0n" as foo } from "./foo";
18+
>foo : 0n
19+
> : ^^
20+
21+
export { foo as "0n" };
22+
>foo : 0n
23+
> : ^^
24+
>"0n" : 0n
25+
> : ^^
26+
27+
=== badImport.ts ===
28+
import { 0n as foo } from "./foo";
29+
>0n as foo : foo
30+
> : ^^^
31+
>0n : 0n
32+
> : ^^
33+
>from : any
34+
> : ^^^
35+
>"./foo" : "./foo"
36+
> : ^^^^^^^
37+
38+
=== badImport2.ts ===
39+
import { foo as 0n } from "./foo";
40+
>foo : any
41+
> : ^^^
42+
> : any
43+
> : ^^^
44+
>from : any
45+
> : ^^^
46+
>"./foo" : "./foo"
47+
> : ^^^^^^^
48+
49+
=== badExport.ts ===
50+
export { foo as 0n };
51+
>foo : any
52+
> : ^^^
53+
> : any
54+
> : ^^^
55+
>0n : 0n
56+
> : ^^
57+
58+
=== badExport2.ts ===
59+
export { 0n as foo };
60+
>0n as foo : foo
61+
> : ^^^
62+
>0n : 0n
63+
> : ^^
64+

0 commit comments

Comments
 (0)