From 55c3ec3e94983bcc7cca79bf8e5181f20722134e Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Mon, 25 Jun 2018 10:58:05 +0200 Subject: [PATCH] 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; +}