From 55c3ec3e94983bcc7cca79bf8e5181f20722134e Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Mon, 25 Jun 2018 10:58:05 +0200 Subject: [PATCH 1/4] Fix decorator design:types emit for type variables. Previously, TypeScript would resolve the reified types for the `design:types` decorator emit in the regular `currentScope`. That scope does not include class declaration bodies. However when reifying types, class declarations do introduce a new scope for any `TypeVariable`s declared on them. Because TS resolved the EntityName for such types against the parent scope (e.g. the source file), not the class scope, TypeScript would either fail to resolve the type (giving `TypeReferenceSerializationKind.Unknown`), or incorrectly resolve to a different, accidentally matching symbol in the outer scope (giving `TypeWithConstructSignatureAndValue`). This would result in an emit referencing an undeclared symbol, or mis-referencing the wrong symbol. __metadata("design:type", typeof (_a = typeof TypeVariable !== "undefined" && TypeVariable) === "function" && _a || Object) __metadata("design:type", TypeVariable) This change special cases `currentScope` for `serializeTypeReferenceNode` to use a class scope, if present. This changes the emit for a `TypeVariable` back to `Object`: __metadata("design:type", Object) --- src/compiler/transformers/ts.ts | 11 +++++- ...atorMetadataGenericTypeVariable.errors.txt | 11 ++++++ .../decoratorMetadataGenericTypeVariable.js | 29 ++++++++++++++ ...coratorMetadataGenericTypeVariable.symbols | 11 ++++++ ...decoratorMetadataGenericTypeVariable.types | 13 +++++++ ...adataGenericTypeVariableDefault.errors.txt | 11 ++++++ ...ratorMetadataGenericTypeVariableDefault.js | 29 ++++++++++++++ ...MetadataGenericTypeVariableDefault.symbols | 11 ++++++ ...orMetadataGenericTypeVariableDefault.types | 13 +++++++ ...adataGenericTypeVariableInScope.errors.txt | 14 +++++++ ...ratorMetadataGenericTypeVariableInScope.js | 38 +++++++++++++++++++ ...MetadataGenericTypeVariableInScope.symbols | 15 ++++++++ ...orMetadataGenericTypeVariableInScope.types | 17 +++++++++ .../decoratorMetadataGenericTypeVariable.ts | 7 ++++ ...ratorMetadataGenericTypeVariableDefault.ts | 7 ++++ ...ratorMetadataGenericTypeVariableInScope.ts | 10 +++++ 16 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/decoratorMetadataGenericTypeVariable.errors.txt create mode 100644 tests/baselines/reference/decoratorMetadataGenericTypeVariable.js create mode 100644 tests/baselines/reference/decoratorMetadataGenericTypeVariable.symbols create mode 100644 tests/baselines/reference/decoratorMetadataGenericTypeVariable.types create mode 100644 tests/baselines/reference/decoratorMetadataGenericTypeVariableDefault.errors.txt create mode 100644 tests/baselines/reference/decoratorMetadataGenericTypeVariableDefault.js create mode 100644 tests/baselines/reference/decoratorMetadataGenericTypeVariableDefault.symbols create mode 100644 tests/baselines/reference/decoratorMetadataGenericTypeVariableDefault.types create mode 100644 tests/baselines/reference/decoratorMetadataGenericTypeVariableInScope.errors.txt create mode 100644 tests/baselines/reference/decoratorMetadataGenericTypeVariableInScope.js create mode 100644 tests/baselines/reference/decoratorMetadataGenericTypeVariableInScope.symbols create mode 100644 tests/baselines/reference/decoratorMetadataGenericTypeVariableInScope.types create mode 100644 tests/cases/compiler/decoratorMetadataGenericTypeVariable.ts create mode 100644 tests/cases/compiler/decoratorMetadataGenericTypeVariableDefault.ts create mode 100644 tests/cases/compiler/decoratorMetadataGenericTypeVariableInScope.ts diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 4712be940fe..ebf5e662517 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -1969,7 +1969,16 @@ namespace ts { * @param node The type reference node. */ function serializeTypeReferenceNode(node: TypeReferenceNode): SerializedTypeNode { - const kind = resolver.getTypeReferenceSerializationKind(node.typeName, currentScope); + // node might be a reference to type variable, which can be scoped to a class declaration, in addition to the regular + // TypeScript scopes. Walk up the AST to find the next class and use that as the lookup scope. + let scope: Node = node; + while (scope.parent && scope !== currentScope) { + scope = scope.parent; + if (isClassDeclaration(scope)) { + break; + } + } + const kind = resolver.getTypeReferenceSerializationKind(node.typeName, scope); switch (kind) { case TypeReferenceSerializationKind.Unknown: const serialized = serializeEntityNameAsExpression(node.typeName, /*useFallback*/ true); diff --git a/tests/baselines/reference/decoratorMetadataGenericTypeVariable.errors.txt b/tests/baselines/reference/decoratorMetadataGenericTypeVariable.errors.txt new file mode 100644 index 00000000000..77258e37a9f --- /dev/null +++ b/tests/baselines/reference/decoratorMetadataGenericTypeVariable.errors.txt @@ -0,0 +1,11 @@ +tests/cases/compiler/decoratorMetadataGenericTypeVariable.ts(2,4): error TS2304: Cannot find name 'Decorate'. + + +==== tests/cases/compiler/decoratorMetadataGenericTypeVariable.ts (1 errors) ==== + export class C { + @Decorate + ~~~~~~~~ +!!! error TS2304: Cannot find name 'Decorate'. + member: TypeVariable; + } + \ No newline at end of file diff --git a/tests/baselines/reference/decoratorMetadataGenericTypeVariable.js b/tests/baselines/reference/decoratorMetadataGenericTypeVariable.js new file mode 100644 index 00000000000..08d4f4a856f --- /dev/null +++ b/tests/baselines/reference/decoratorMetadataGenericTypeVariable.js @@ -0,0 +1,29 @@ +//// [decoratorMetadataGenericTypeVariable.ts] +export class C { + @Decorate + member: TypeVariable; +} + + +//// [decoratorMetadataGenericTypeVariable.js] +"use strict"; +var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (this && this.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; +exports.__esModule = true; +var C = /** @class */ (function () { + function C() { + } + __decorate([ + Decorate, + __metadata("design:type", Object) + ], C.prototype, "member"); + return C; +}()); +exports.C = C; diff --git a/tests/baselines/reference/decoratorMetadataGenericTypeVariable.symbols b/tests/baselines/reference/decoratorMetadataGenericTypeVariable.symbols new file mode 100644 index 00000000000..d01f6d5523a --- /dev/null +++ b/tests/baselines/reference/decoratorMetadataGenericTypeVariable.symbols @@ -0,0 +1,11 @@ +=== tests/cases/compiler/decoratorMetadataGenericTypeVariable.ts === +export class C { +>C : Symbol(C, Decl(decoratorMetadataGenericTypeVariable.ts, 0, 0)) +>TypeVariable : Symbol(TypeVariable, Decl(decoratorMetadataGenericTypeVariable.ts, 0, 15)) + + @Decorate + member: TypeVariable; +>member : Symbol(C.member, Decl(decoratorMetadataGenericTypeVariable.ts, 0, 30)) +>TypeVariable : Symbol(TypeVariable, Decl(decoratorMetadataGenericTypeVariable.ts, 0, 15)) +} + diff --git a/tests/baselines/reference/decoratorMetadataGenericTypeVariable.types b/tests/baselines/reference/decoratorMetadataGenericTypeVariable.types new file mode 100644 index 00000000000..8d4965f9942 --- /dev/null +++ b/tests/baselines/reference/decoratorMetadataGenericTypeVariable.types @@ -0,0 +1,13 @@ +=== tests/cases/compiler/decoratorMetadataGenericTypeVariable.ts === +export class C { +>C : C +>TypeVariable : TypeVariable + + @Decorate +>Decorate : any + + member: TypeVariable; +>member : TypeVariable +>TypeVariable : TypeVariable +} + diff --git a/tests/baselines/reference/decoratorMetadataGenericTypeVariableDefault.errors.txt b/tests/baselines/reference/decoratorMetadataGenericTypeVariableDefault.errors.txt new file mode 100644 index 00000000000..324aafbc6ed --- /dev/null +++ b/tests/baselines/reference/decoratorMetadataGenericTypeVariableDefault.errors.txt @@ -0,0 +1,11 @@ +tests/cases/compiler/decoratorMetadataGenericTypeVariableDefault.ts(2,4): error TS2304: Cannot find name 'Decorate'. + + +==== tests/cases/compiler/decoratorMetadataGenericTypeVariableDefault.ts (1 errors) ==== + export class C { + @Decorate + ~~~~~~~~ +!!! error TS2304: Cannot find name 'Decorate'. + member: TypeVariable; + } + \ No newline at end of file diff --git a/tests/baselines/reference/decoratorMetadataGenericTypeVariableDefault.js b/tests/baselines/reference/decoratorMetadataGenericTypeVariableDefault.js new file mode 100644 index 00000000000..9c3c309d503 --- /dev/null +++ b/tests/baselines/reference/decoratorMetadataGenericTypeVariableDefault.js @@ -0,0 +1,29 @@ +//// [decoratorMetadataGenericTypeVariableDefault.ts] +export class C { + @Decorate + member: TypeVariable; +} + + +//// [decoratorMetadataGenericTypeVariableDefault.js] +"use strict"; +var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (this && this.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; +exports.__esModule = true; +var C = /** @class */ (function () { + function C() { + } + __decorate([ + Decorate, + __metadata("design:type", Object) + ], C.prototype, "member"); + return C; +}()); +exports.C = C; diff --git a/tests/baselines/reference/decoratorMetadataGenericTypeVariableDefault.symbols b/tests/baselines/reference/decoratorMetadataGenericTypeVariableDefault.symbols new file mode 100644 index 00000000000..178fc2efeb0 --- /dev/null +++ b/tests/baselines/reference/decoratorMetadataGenericTypeVariableDefault.symbols @@ -0,0 +1,11 @@ +=== tests/cases/compiler/decoratorMetadataGenericTypeVariableDefault.ts === +export class C { +>C : Symbol(C, Decl(decoratorMetadataGenericTypeVariableDefault.ts, 0, 0)) +>TypeVariable : Symbol(TypeVariable, Decl(decoratorMetadataGenericTypeVariableDefault.ts, 0, 15)) + + @Decorate + member: TypeVariable; +>member : Symbol(C.member, Decl(decoratorMetadataGenericTypeVariableDefault.ts, 0, 39)) +>TypeVariable : Symbol(TypeVariable, Decl(decoratorMetadataGenericTypeVariableDefault.ts, 0, 15)) +} + diff --git a/tests/baselines/reference/decoratorMetadataGenericTypeVariableDefault.types b/tests/baselines/reference/decoratorMetadataGenericTypeVariableDefault.types new file mode 100644 index 00000000000..1bbe1b3fb70 --- /dev/null +++ b/tests/baselines/reference/decoratorMetadataGenericTypeVariableDefault.types @@ -0,0 +1,13 @@ +=== tests/cases/compiler/decoratorMetadataGenericTypeVariableDefault.ts === +export class C { +>C : C +>TypeVariable : TypeVariable + + @Decorate +>Decorate : any + + member: TypeVariable; +>member : TypeVariable +>TypeVariable : TypeVariable +} + diff --git a/tests/baselines/reference/decoratorMetadataGenericTypeVariableInScope.errors.txt b/tests/baselines/reference/decoratorMetadataGenericTypeVariableInScope.errors.txt new file mode 100644 index 00000000000..9a5016af1fa --- /dev/null +++ b/tests/baselines/reference/decoratorMetadataGenericTypeVariableInScope.errors.txt @@ -0,0 +1,14 @@ +tests/cases/compiler/decoratorMetadataGenericTypeVariableInScope.ts(5,4): error TS2304: Cannot find name 'Decorate'. + + +==== tests/cases/compiler/decoratorMetadataGenericTypeVariableInScope.ts (1 errors) ==== + // Unused, but could collide with the named type argument below. + class TypeVariable {} + + export class C { + @Decorate + ~~~~~~~~ +!!! error TS2304: Cannot find name 'Decorate'. + member: TypeVariable; + } + \ No newline at end of file diff --git a/tests/baselines/reference/decoratorMetadataGenericTypeVariableInScope.js b/tests/baselines/reference/decoratorMetadataGenericTypeVariableInScope.js new file mode 100644 index 00000000000..aa5dd1db522 --- /dev/null +++ b/tests/baselines/reference/decoratorMetadataGenericTypeVariableInScope.js @@ -0,0 +1,38 @@ +//// [decoratorMetadataGenericTypeVariableInScope.ts] +// Unused, but could collide with the named type argument below. +class TypeVariable {} + +export class C { + @Decorate + member: TypeVariable; +} + + +//// [decoratorMetadataGenericTypeVariableInScope.js] +"use strict"; +var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (this && this.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; +exports.__esModule = true; +// Unused, but could collide with the named type argument below. +var TypeVariable = /** @class */ (function () { + function TypeVariable() { + } + return TypeVariable; +}()); +var C = /** @class */ (function () { + function C() { + } + __decorate([ + Decorate, + __metadata("design:type", Object) + ], C.prototype, "member"); + return C; +}()); +exports.C = C; diff --git a/tests/baselines/reference/decoratorMetadataGenericTypeVariableInScope.symbols b/tests/baselines/reference/decoratorMetadataGenericTypeVariableInScope.symbols new file mode 100644 index 00000000000..3f415fb440b --- /dev/null +++ b/tests/baselines/reference/decoratorMetadataGenericTypeVariableInScope.symbols @@ -0,0 +1,15 @@ +=== tests/cases/compiler/decoratorMetadataGenericTypeVariableInScope.ts === +// Unused, but could collide with the named type argument below. +class TypeVariable {} +>TypeVariable : Symbol(TypeVariable, Decl(decoratorMetadataGenericTypeVariableInScope.ts, 0, 0)) + +export class C { +>C : Symbol(C, Decl(decoratorMetadataGenericTypeVariableInScope.ts, 1, 21)) +>TypeVariable : Symbol(TypeVariable, Decl(decoratorMetadataGenericTypeVariableInScope.ts, 3, 15)) + + @Decorate + member: TypeVariable; +>member : Symbol(C.member, Decl(decoratorMetadataGenericTypeVariableInScope.ts, 3, 30)) +>TypeVariable : Symbol(TypeVariable, Decl(decoratorMetadataGenericTypeVariableInScope.ts, 3, 15)) +} + diff --git a/tests/baselines/reference/decoratorMetadataGenericTypeVariableInScope.types b/tests/baselines/reference/decoratorMetadataGenericTypeVariableInScope.types new file mode 100644 index 00000000000..b81214cd170 --- /dev/null +++ b/tests/baselines/reference/decoratorMetadataGenericTypeVariableInScope.types @@ -0,0 +1,17 @@ +=== tests/cases/compiler/decoratorMetadataGenericTypeVariableInScope.ts === +// Unused, but could collide with the named type argument below. +class TypeVariable {} +>TypeVariable : TypeVariable + +export class C { +>C : C +>TypeVariable : TypeVariable + + @Decorate +>Decorate : any + + member: TypeVariable; +>member : TypeVariable +>TypeVariable : TypeVariable +} + diff --git a/tests/cases/compiler/decoratorMetadataGenericTypeVariable.ts b/tests/cases/compiler/decoratorMetadataGenericTypeVariable.ts new file mode 100644 index 00000000000..99e603d490e --- /dev/null +++ b/tests/cases/compiler/decoratorMetadataGenericTypeVariable.ts @@ -0,0 +1,7 @@ +// @experimentalDecorators: true +// @emitDecoratorMetadata: true + +export class C { + @Decorate + member: TypeVariable; +} diff --git a/tests/cases/compiler/decoratorMetadataGenericTypeVariableDefault.ts b/tests/cases/compiler/decoratorMetadataGenericTypeVariableDefault.ts new file mode 100644 index 00000000000..efb7be349c4 --- /dev/null +++ b/tests/cases/compiler/decoratorMetadataGenericTypeVariableDefault.ts @@ -0,0 +1,7 @@ +// @experimentalDecorators: true +// @emitDecoratorMetadata: true + +export class C { + @Decorate + member: TypeVariable; +} diff --git a/tests/cases/compiler/decoratorMetadataGenericTypeVariableInScope.ts b/tests/cases/compiler/decoratorMetadataGenericTypeVariableInScope.ts new file mode 100644 index 00000000000..fac33aa5e24 --- /dev/null +++ b/tests/cases/compiler/decoratorMetadataGenericTypeVariableInScope.ts @@ -0,0 +1,10 @@ +// @experimentalDecorators: true +// @emitDecoratorMetadata: true + +// Unused, but could collide with the named type argument below. +class TypeVariable {} + +export class C { + @Decorate + member: TypeVariable; +} From f1fe0b8116fed21d3df305bf18bcbf54898c7236 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Tue, 26 Jun 2018 15:51:37 +0200 Subject: [PATCH 2/4] use better scope --- src/compiler/transformers/ts.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index ebf5e662517..6d724750b00 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -61,7 +61,7 @@ namespace ts { let currentSourceFile: SourceFile; let currentNamespace: ModuleDeclaration; let currentNamespaceContainerName: Identifier; - let currentScope: SourceFile | Block | ModuleBlock | CaseBlock; + let currentScope: SourceFile | Block | ModuleBlock | CaseBlock | ClassDeclaration; let currentScopeFirstDeclarationsOfName: UnderscoreEscapedMap | undefined; /** @@ -166,6 +166,9 @@ namespace ts { case SyntaxKind.ClassDeclaration: case SyntaxKind.FunctionDeclaration: + if (isClassDeclaration(node)) { + currentScope = node; + } if (hasModifier(node, ModifierFlags.Ambient)) { break; } @@ -1971,13 +1974,13 @@ namespace ts { function serializeTypeReferenceNode(node: TypeReferenceNode): SerializedTypeNode { // node might be a reference to type variable, which can be scoped to a class declaration, in addition to the regular // TypeScript scopes. Walk up the AST to find the next class and use that as the lookup scope. - let scope: Node = node; - while (scope.parent && scope !== currentScope) { - scope = scope.parent; - if (isClassDeclaration(scope)) { - break; - } - } + let scope: Node = currentScope; + // while (scope.parent && scope !== currentScope) { + // scope = scope.parent; + // if (isClassDeclaration(scope)) { + // break; + // } + // } const kind = resolver.getTypeReferenceSerializationKind(node.typeName, scope); switch (kind) { case TypeReferenceSerializationKind.Unknown: From 6a24eabd1863d92b572b98097995622e566d0108 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Tue, 26 Jun 2018 16:33:36 +0200 Subject: [PATCH 3/4] Set current scope for classes. --- src/compiler/transformers/ts.ts | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 6d724750b00..5a60916167f 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -166,9 +166,6 @@ namespace ts { case SyntaxKind.ClassDeclaration: case SyntaxKind.FunctionDeclaration: - if (isClassDeclaration(node)) { - currentScope = node; - } if (hasModifier(node, ModifierFlags.Ambient)) { break; } @@ -183,6 +180,10 @@ namespace ts { // programs may also have an undefined name. Debug.assert(node.kind === SyntaxKind.ClassDeclaration || hasModifier(node, ModifierFlags.Default)); } + if (isClassDeclaration(node)) { + // XXX: should probably also cover interfaces and type aliases that can have type variables? + currentScope = node; + } break; } @@ -1972,16 +1973,7 @@ namespace ts { * @param node The type reference node. */ function serializeTypeReferenceNode(node: TypeReferenceNode): SerializedTypeNode { - // node might be a reference to type variable, which can be scoped to a class declaration, in addition to the regular - // TypeScript scopes. Walk up the AST to find the next class and use that as the lookup scope. - let scope: Node = currentScope; - // while (scope.parent && scope !== currentScope) { - // scope = scope.parent; - // if (isClassDeclaration(scope)) { - // break; - // } - // } - const kind = resolver.getTypeReferenceSerializationKind(node.typeName, scope); + const kind = resolver.getTypeReferenceSerializationKind(node.typeName, currentScope); switch (kind) { case TypeReferenceSerializationKind.Unknown: const serialized = serializeEntityNameAsExpression(node.typeName, /*useFallback*/ true); From a7be62f9db58ac0f64f5412d5094ed15412e70fe Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 26 Jun 2018 12:24:55 -0700 Subject: [PATCH 4/4] Track name scope aloneside lexical scope --- src/compiler/transformers/ts.ts | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 5a60916167f..e810b6ca4c6 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -61,7 +61,8 @@ namespace ts { let currentSourceFile: SourceFile; let currentNamespace: ModuleDeclaration; let currentNamespaceContainerName: Identifier; - let currentScope: SourceFile | Block | ModuleBlock | CaseBlock | ClassDeclaration; + let currentLexicalScope: SourceFile | Block | ModuleBlock | CaseBlock; + let currentNameScope: ClassDeclaration | undefined; let currentScopeFirstDeclarationsOfName: UnderscoreEscapedMap | undefined; /** @@ -132,7 +133,8 @@ namespace ts { */ function saveStateAndInvoke(node: Node, f: (node: Node) => T): T { // Save state - const savedCurrentScope = currentScope; + const savedCurrentScope = currentLexicalScope; + const savedCurrentNameScope = currentNameScope; const savedCurrentScopeFirstDeclarationsOfName = currentScopeFirstDeclarationsOfName; // Handle state changes before visiting a node. @@ -141,11 +143,12 @@ namespace ts { const visited = f(node); // Restore state - if (currentScope !== savedCurrentScope) { + if (currentLexicalScope !== savedCurrentScope) { currentScopeFirstDeclarationsOfName = savedCurrentScopeFirstDeclarationsOfName; } - currentScope = savedCurrentScope; + currentLexicalScope = savedCurrentScope; + currentNameScope = savedCurrentNameScope; return visited; } @@ -160,7 +163,8 @@ namespace ts { case SyntaxKind.CaseBlock: case SyntaxKind.ModuleBlock: case SyntaxKind.Block: - currentScope = node; + currentLexicalScope = node; + currentNameScope = undefined; currentScopeFirstDeclarationsOfName = undefined; break; @@ -182,7 +186,7 @@ namespace ts { } if (isClassDeclaration(node)) { // XXX: should probably also cover interfaces and type aliases that can have type variables? - currentScope = node; + currentNameScope = node; } break; @@ -1973,7 +1977,7 @@ namespace ts { * @param node The type reference node. */ function serializeTypeReferenceNode(node: TypeReferenceNode): SerializedTypeNode { - const kind = resolver.getTypeReferenceSerializationKind(node.typeName, currentScope); + const kind = resolver.getTypeReferenceSerializationKind(node.typeName, currentNameScope || currentLexicalScope); switch (kind) { case TypeReferenceSerializationKind.Unknown: const serialized = serializeEntityNameAsExpression(node.typeName, /*useFallback*/ true); @@ -2037,7 +2041,7 @@ namespace ts { const name = getMutableClone(node); name.flags &= ~NodeFlags.Synthesized; name.original = undefined; - name.parent = getParseTreeNode(currentScope); // ensure the parent is set to a parse tree node. + name.parent = getParseTreeNode(currentLexicalScope); // ensure the parent is set to a parse tree node. if (useFallback) { return createLogicalAnd( createStrictInequality( @@ -2624,7 +2628,7 @@ namespace ts { // enum body. if (addVarForEnumOrModuleDeclaration(statements, node)) { // We should still emit the comments if we are emitting a system module. - if (moduleKind !== ModuleKind.System || currentScope !== currentSourceFile) { + if (moduleKind !== ModuleKind.System || currentLexicalScope !== currentSourceFile) { emitFlags |= EmitFlags.NoLeadingComments; } } @@ -2837,7 +2841,7 @@ namespace ts { createVariableDeclaration( getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true) ) - ], currentScope.kind === SyntaxKind.SourceFile ? NodeFlags.None : NodeFlags.Let) + ], currentLexicalScope.kind === SyntaxKind.SourceFile ? NodeFlags.None : NodeFlags.Let) ); setOriginalNode(statement, node); @@ -2913,7 +2917,7 @@ namespace ts { // module body. if (addVarForEnumOrModuleDeclaration(statements, node)) { // We should still emit the comments if we are emitting a system module. - if (moduleKind !== ModuleKind.System || currentScope !== currentSourceFile) { + if (moduleKind !== ModuleKind.System || currentLexicalScope !== currentSourceFile) { emitFlags |= EmitFlags.NoLeadingComments; } }