From c6d712d0c921a34ffa969b380481d126ad8438a2 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Mon, 30 Sep 2019 16:20:15 -0500 Subject: [PATCH 1/7] Fix binding well-known symbols by element access --- src/compiler/types.ts | 15 +++++++++++++-- src/compiler/utilities.ts | 6 ++++-- src/services/navigationBar.ts | 4 ++-- tests/cases/compiler/wellKnownSymbolExpando.ts | 5 +++++ 4 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 tests/cases/compiler/wellKnownSymbolExpando.ts diff --git a/src/compiler/types.ts b/src/compiler/types.ts index d034b3544e646..ebd2ef5845dc1 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -819,7 +819,14 @@ namespace ts { export type PropertyName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName; - export type DeclarationName = Identifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | ElementAccessExpression | BindingPattern; + export type DeclarationName = + | Identifier + | StringLiteralLike + | NumericLiteral + | ComputedPropertyName + | ElementAccessExpression + | BindingPattern + | WellKnownSymbolExpression; export interface Declaration extends Node { _declarationBrand: any; @@ -1884,13 +1891,17 @@ namespace ts { | CallChainRoot ; + /** @internal */ + export interface WellKnownSymbolExpression extends PropertyAccessExpression { + expression: Identifier & { escapedText: "Symbol" }; + } /** @internal */ export type BindableObjectDefinePropertyCall = CallExpression & { arguments: { 0: BindableStaticNameExpression, 1: StringLiteralLike | NumericLiteral, 2: ObjectLiteralExpression } }; /** @internal */ export type BindableStaticNameExpression = EntityNameExpression | BindableStaticElementAccessExpression; /** @internal */ export type LiteralLikeElementAccessExpression = ElementAccessExpression & Declaration & { - argumentExpression: StringLiteralLike | NumericLiteral; + argumentExpression: StringLiteralLike | NumericLiteral | WellKnownSymbolExpression; }; /** @internal */ export type BindableStaticElementAccessExpression = LiteralLikeElementAccessExpression & { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index a0988cfa7e319..a58ef5dc25d10 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2068,7 +2068,9 @@ namespace ts { } export function isLiteralLikeElementAccess(node: Node): node is LiteralLikeElementAccessExpression { - return isElementAccessExpression(node) && isStringOrNumericLiteralLike(node.argumentExpression); + return isElementAccessExpression(node) && ( + isStringOrNumericLiteralLike(node.argumentExpression) || + isWellKnownSymbolSyntactically(node.argumentExpression)); } export function isBindableStaticAccessExpression(node: Node, excludeThisKeyword?: boolean): node is BindableStaticAccessExpression { @@ -2901,7 +2903,7 @@ namespace ts { * Symbol.name * where Symbol is literally the word "Symbol", and name is any identifierName */ - export function isWellKnownSymbolSyntactically(node: Expression): boolean { + export function isWellKnownSymbolSyntactically(node: Expression): node is WellKnownSymbolExpression { return isPropertyAccessExpression(node) && isESSymbolIdentifier(node.expression); } diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts index 6de1de99cd759..03b9d6216c874 100644 --- a/src/services/navigationBar.ts +++ b/src/services/navigationBar.ts @@ -136,7 +136,7 @@ namespace ts.NavigationBar { for (let i = 0; i < depth; i++) endNode(); } function startNestedNodes(targetNode: Node, entityName: BindableStaticNameExpression) { - const names: PropertyNameLiteral[] = []; + const names: (PropertyNameLiteral | WellKnownSymbolExpression)[] = []; while (!isPropertyNameLiteral(entityName)) { const name = getNameOrArgument(entityName); const nameText = getElementOrPropertyAccessName(entityName); @@ -334,7 +334,7 @@ namespace ts.NavigationBar { assignmentTarget; let depth = 0; - let className: PropertyNameLiteral; + let className: PropertyNameLiteral | WellKnownSymbolExpression; // If we see a prototype assignment, start tracking the target as a class // This is only done for simple classes not nested assignments. if (isIdentifier(prototypeAccess.expression)) { diff --git a/tests/cases/compiler/wellKnownSymbolExpando.ts b/tests/cases/compiler/wellKnownSymbolExpando.ts new file mode 100644 index 0000000000000..b80fa2bb8b28d --- /dev/null +++ b/tests/cases/compiler/wellKnownSymbolExpando.ts @@ -0,0 +1,5 @@ +// @noEmit: true +// @target: esnext + +function f() {} +f[Symbol.iterator] = function() {} From 500cdcc091dff48caa7669fe2d5a0e3e8781606f Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Mon, 30 Sep 2019 16:24:04 -0500 Subject: [PATCH 2/7] Add navigationBar test --- .vscode/settings.json | 3 +- .../navigationBarWellKnownSymbolExpando.ts | 53 +++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 tests/cases/fourslash/navigationBarWellKnownSymbolExpando.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 14f7984e7e9c4..5cced43bd70c9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,5 +8,6 @@ "eslint.options": { "rulePaths": ["./scripts/eslint/built/rules/"], "ext": [".ts"] - } + }, + "typescript.tsdk": "built/local" } \ No newline at end of file diff --git a/tests/cases/fourslash/navigationBarWellKnownSymbolExpando.ts b/tests/cases/fourslash/navigationBarWellKnownSymbolExpando.ts new file mode 100644 index 0000000000000..a6b9cadc1242f --- /dev/null +++ b/tests/cases/fourslash/navigationBarWellKnownSymbolExpando.ts @@ -0,0 +1,53 @@ +/// + +////function f() {} +////f[Symbol.iterator] = function() {} + +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "f", + "kind": "class", + "childItems": [ + { + "text": "constructor", + "kind": "constructor" + }, + { + "text": "[Symbol.iterator]", + "kind": "function" + } + ] + } + ] +}); + +verify.navigationBar([ + { + "text": "", + "kind": "script", + "childItems": [ + { + "text": "f", + "kind": "class" + } + ] + }, + { + "text": "f", + "kind": "class", + "childItems": [ + { + "text": "constructor", + "kind": "constructor" + }, + { + "text": "[Symbol.iterator]", + "kind": "function" + } + ], + "indent": 1 + } +]); From a44893d7a232b13c6ca8f094a45c174b4357d0f5 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Mon, 30 Sep 2019 16:25:10 -0500 Subject: [PATCH 3/7] Revert settings.json change --- .vscode/settings.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 5cced43bd70c9..14f7984e7e9c4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,6 +8,5 @@ "eslint.options": { "rulePaths": ["./scripts/eslint/built/rules/"], "ext": [".ts"] - }, - "typescript.tsdk": "built/local" + } } \ No newline at end of file From b3decb6357f649e7b199f3a1137b31a46cd0d5fd Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Mon, 30 Sep 2019 16:26:26 -0500 Subject: [PATCH 4/7] Accept baselines --- .../reference/wellKnownSymbolExpando.symbols | 10 ++++++++++ .../reference/wellKnownSymbolExpando.types | 13 +++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 tests/baselines/reference/wellKnownSymbolExpando.symbols create mode 100644 tests/baselines/reference/wellKnownSymbolExpando.types diff --git a/tests/baselines/reference/wellKnownSymbolExpando.symbols b/tests/baselines/reference/wellKnownSymbolExpando.symbols new file mode 100644 index 0000000000000..b343b2047f643 --- /dev/null +++ b/tests/baselines/reference/wellKnownSymbolExpando.symbols @@ -0,0 +1,10 @@ +=== tests/cases/compiler/wellKnownSymbolExpando.ts === +function f() {} +>f : Symbol(f, Decl(wellKnownSymbolExpando.ts, 0, 0), Decl(wellKnownSymbolExpando.ts, 0, 15)) + +f[Symbol.iterator] = function() {} +>f : Symbol(f, Decl(wellKnownSymbolExpando.ts, 0, 0), Decl(wellKnownSymbolExpando.ts, 0, 15)) +>Symbol.iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --)) +>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --)) +>iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --)) + diff --git a/tests/baselines/reference/wellKnownSymbolExpando.types b/tests/baselines/reference/wellKnownSymbolExpando.types new file mode 100644 index 0000000000000..9689500c37fe2 --- /dev/null +++ b/tests/baselines/reference/wellKnownSymbolExpando.types @@ -0,0 +1,13 @@ +=== tests/cases/compiler/wellKnownSymbolExpando.ts === +function f() {} +>f : typeof f + +f[Symbol.iterator] = function() {} +>f[Symbol.iterator] = function() {} : () => void +>f[Symbol.iterator] : error +>f : typeof f +>Symbol.iterator : symbol +>Symbol : SymbolConstructor +>iterator : symbol +>function() {} : () => void + From 0356be6d8a6616b2ebcbb9de61b7589c72aceff8 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Mon, 30 Sep 2019 17:09:30 -0500 Subject: [PATCH 5/7] Actually make it bind --- src/compiler/binder.ts | 3 +++ src/compiler/utilities.ts | 2 +- tests/baselines/reference/wellKnownSymbolExpando.types | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 47950566dfdaa..cec04589a2cc7 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -344,6 +344,9 @@ namespace ts { Debug.assert(isWellKnownSymbolSyntactically(nameExpression)); return getPropertyNameForKnownSymbolName(idText((nameExpression).name)); } + if (isWellKnownSymbolSyntactically(name)) { + return getPropertyNameForKnownSymbolName(idText(name.name)); + } return isPropertyNameLiteral(name) ? getEscapedTextOfIdentifierOrLiteral(name) : undefined; } switch (node.kind) { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index a58ef5dc25d10..9549d313df6b9 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2903,7 +2903,7 @@ namespace ts { * Symbol.name * where Symbol is literally the word "Symbol", and name is any identifierName */ - export function isWellKnownSymbolSyntactically(node: Expression): node is WellKnownSymbolExpression { + export function isWellKnownSymbolSyntactically(node: Node): node is WellKnownSymbolExpression { return isPropertyAccessExpression(node) && isESSymbolIdentifier(node.expression); } diff --git a/tests/baselines/reference/wellKnownSymbolExpando.types b/tests/baselines/reference/wellKnownSymbolExpando.types index 9689500c37fe2..f0a1c32a7f97c 100644 --- a/tests/baselines/reference/wellKnownSymbolExpando.types +++ b/tests/baselines/reference/wellKnownSymbolExpando.types @@ -4,7 +4,7 @@ function f() {} f[Symbol.iterator] = function() {} >f[Symbol.iterator] = function() {} : () => void ->f[Symbol.iterator] : error +>f[Symbol.iterator] : () => void >f : typeof f >Symbol.iterator : symbol >Symbol : SymbolConstructor From 6da68343c63bb622ed079999e7fd6a6c04284120 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 30 Sep 2019 15:37:58 -0700 Subject: [PATCH 6/7] Accept API baselines --- tests/baselines/reference/api/tsserverlibrary.d.ts | 2 +- tests/baselines/reference/api/typescript.d.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 3616e96d9d812..705ea3d6966f5 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -548,7 +548,7 @@ declare namespace ts { } export type EntityName = Identifier | QualifiedName; export type PropertyName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName; - export type DeclarationName = Identifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | ElementAccessExpression | BindingPattern; + export type DeclarationName = Identifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | ElementAccessExpression | BindingPattern | WellKnownSymbolExpression; export interface Declaration extends Node { _declarationBrand: any; } diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 8027692181810..c906aa44d8ad2 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -548,7 +548,7 @@ declare namespace ts { } export type EntityName = Identifier | QualifiedName; export type PropertyName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName; - export type DeclarationName = Identifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | ElementAccessExpression | BindingPattern; + export type DeclarationName = Identifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | ElementAccessExpression | BindingPattern | WellKnownSymbolExpression; export interface Declaration extends Node { _declarationBrand: any; } From 1222c1b433c0865ed9d0ee1e985e25905f4ef424 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 30 Sep 2019 15:56:32 -0700 Subject: [PATCH 7/7] Dont use internal name in API --- src/compiler/types.ts | 2 +- tests/baselines/reference/api/tsserverlibrary.d.ts | 2 +- tests/baselines/reference/api/typescript.d.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ebd2ef5845dc1..78891d7dfe255 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -826,7 +826,7 @@ namespace ts { | ComputedPropertyName | ElementAccessExpression | BindingPattern - | WellKnownSymbolExpression; + | EntityNameExpression; export interface Declaration extends Node { _declarationBrand: any; diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 705ea3d6966f5..d465c84dcc64d 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -548,7 +548,7 @@ declare namespace ts { } export type EntityName = Identifier | QualifiedName; export type PropertyName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName; - export type DeclarationName = Identifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | ElementAccessExpression | BindingPattern | WellKnownSymbolExpression; + export type DeclarationName = Identifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | ElementAccessExpression | BindingPattern | EntityNameExpression; export interface Declaration extends Node { _declarationBrand: any; } diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index c906aa44d8ad2..21688456bacb8 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -548,7 +548,7 @@ declare namespace ts { } export type EntityName = Identifier | QualifiedName; export type PropertyName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName; - export type DeclarationName = Identifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | ElementAccessExpression | BindingPattern | WellKnownSymbolExpression; + export type DeclarationName = Identifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | ElementAccessExpression | BindingPattern | EntityNameExpression; export interface Declaration extends Node { _declarationBrand: any; }