From 9b95d562dd623b5846279c151c3d3f75551960dd Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 31 Jul 2018 18:22:54 -0700 Subject: [PATCH] Fix decorated accessor emit (#26016) (#26103) --- src/compiler/checker.ts | 21 +++++--- src/compiler/transformers/ts.ts | 10 +++- src/compiler/types.ts | 4 +- src/compiler/utilities.ts | 8 +-- .../reference/decoratorOnClassAccessor8.js | 4 +- ...rgetEs6DecoratorMetadataImportNotElided.js | 54 +++++++++++++++++++ ...s6DecoratorMetadataImportNotElided.symbols | 38 +++++++++++++ ...tEs6DecoratorMetadataImportNotElided.types | 40 ++++++++++++++ ...rgetEs6DecoratorMetadataImportNotElided.ts | 18 +++++++ 9 files changed, 181 insertions(+), 16 deletions(-) create mode 100644 tests/baselines/reference/targetEs6DecoratorMetadataImportNotElided.js create mode 100644 tests/baselines/reference/targetEs6DecoratorMetadataImportNotElided.symbols create mode 100644 tests/baselines/reference/targetEs6DecoratorMetadataImportNotElided.types create mode 100644 tests/cases/compiler/targetEs6DecoratorMetadataImportNotElided.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c66d85beb93..305fa8844ea 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5092,20 +5092,25 @@ namespace ts { } } - function getAnnotatedAccessorType(accessor: AccessorDeclaration | undefined): Type | undefined { + function getAnnotatedAccessorTypeNode(accessor: AccessorDeclaration | undefined): TypeNode | undefined { if (accessor) { if (accessor.kind === SyntaxKind.GetAccessor) { const getterTypeAnnotation = getEffectiveReturnTypeNode(accessor); - return getterTypeAnnotation && getTypeFromTypeNode(getterTypeAnnotation); + return getterTypeAnnotation; } else { const setterTypeAnnotation = getEffectiveSetAccessorTypeAnnotationNode(accessor); - return setterTypeAnnotation && getTypeFromTypeNode(setterTypeAnnotation); + return setterTypeAnnotation; } } return undefined; } + function getAnnotatedAccessorType(accessor: AccessorDeclaration | undefined): Type | undefined { + const node = getAnnotatedAccessorTypeNode(accessor); + return node && getTypeFromTypeNode(node); + } + function getAnnotatedAccessorThisParameter(accessor: AccessorDeclaration): Symbol | undefined { const parameter = getAccessorThisParameter(accessor); return parameter && parameter.symbol; @@ -23342,9 +23347,13 @@ namespace ts { } break; - case SyntaxKind.MethodDeclaration: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: + const otherKind = node.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor : SyntaxKind.GetAccessor; + const otherAccessor = getDeclarationOfKind(getSymbolOfNode(node as AccessorDeclaration), otherKind); + markDecoratorMedataDataTypeNodeAsReferenced(getAnnotatedAccessorTypeNode(node as AccessorDeclaration) || otherAccessor && getAnnotatedAccessorTypeNode(otherAccessor)); + break; + case SyntaxKind.MethodDeclaration: for (const parameter of (node).parameters) { markDecoratorMedataDataTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(parameter)); } @@ -27867,8 +27876,8 @@ namespace ts { const otherAccessor = getDeclarationOfKind(getSymbolOfNode(accessor), otherKind); const firstAccessor = otherAccessor && (otherAccessor.pos < accessor.pos) ? otherAccessor : accessor; const secondAccessor = otherAccessor && (otherAccessor.pos < accessor.pos) ? accessor : otherAccessor; - const setAccessor = accessor.kind === SyntaxKind.SetAccessor ? accessor : otherAccessor; - const getAccessor = accessor.kind === SyntaxKind.GetAccessor ? accessor : otherAccessor; + const setAccessor = accessor.kind === SyntaxKind.SetAccessor ? accessor : otherAccessor as SetAccessorDeclaration; + const getAccessor = accessor.kind === SyntaxKind.GetAccessor ? accessor : otherAccessor as GetAccessorDeclaration; return { firstAccessor, secondAccessor, diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 839e740b755..ffe58b2320d 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -1750,6 +1750,12 @@ namespace ts { type SerializedEntityNameAsExpression = Identifier | BinaryExpression | PropertyAccessExpression; type SerializedTypeNode = SerializedEntityNameAsExpression | VoidExpression | ConditionalExpression; + function getAccessorTypeNode(node: AccessorDeclaration) { + const accessors = resolver.getAllAccessorDeclarations(node); + return accessors.setAccessor && getSetAccessorTypeAnnotationNode(accessors.setAccessor) + || accessors.getAccessor && getEffectiveReturnTypeNode(accessors.getAccessor); + } + /** * Serializes the type of a node for use with decorator type metadata. * @@ -1759,10 +1765,10 @@ namespace ts { switch (node.kind) { case SyntaxKind.PropertyDeclaration: case SyntaxKind.Parameter: - case SyntaxKind.GetAccessor: return serializeTypeNode((node).type); case SyntaxKind.SetAccessor: - return serializeTypeNode(getSetAccessorTypeAnnotationNode(node)); + case SyntaxKind.GetAccessor: + return serializeTypeNode(getAccessorTypeNode(node as AccessorDeclaration)); case SyntaxKind.ClassDeclaration: case SyntaxKind.ClassExpression: case SyntaxKind.MethodDeclaration: diff --git a/src/compiler/types.ts b/src/compiler/types.ts index eb8a0c061d5..9f8dfb6546a 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3305,8 +3305,8 @@ namespace ts { export interface AllAccessorDeclarations { firstAccessor: AccessorDeclaration; secondAccessor: AccessorDeclaration | undefined; - getAccessor: AccessorDeclaration | undefined; - setAccessor: AccessorDeclaration | undefined; + getAccessor: GetAccessorDeclaration | undefined; + setAccessor: SetAccessorDeclaration | undefined; } /** Indicates how to serialize the name for a TypeReferenceNode when emitting decorator metadata */ diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 479c662c86e..5addbea23a3 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3293,8 +3293,8 @@ namespace ts { // TODO: GH#18217 let firstAccessor!: AccessorDeclaration; let secondAccessor!: AccessorDeclaration; - let getAccessor!: AccessorDeclaration; - let setAccessor!: AccessorDeclaration; + let getAccessor!: GetAccessorDeclaration; + let setAccessor!: SetAccessorDeclaration; if (hasDynamicName(accessor)) { firstAccessor = accessor; if (accessor.kind === SyntaxKind.GetAccessor) { @@ -3322,11 +3322,11 @@ namespace ts { } if (member.kind === SyntaxKind.GetAccessor && !getAccessor) { - getAccessor = member; + getAccessor = member; } if (member.kind === SyntaxKind.SetAccessor && !setAccessor) { - setAccessor = member; + setAccessor = member; } } } diff --git a/tests/baselines/reference/decoratorOnClassAccessor8.js b/tests/baselines/reference/decoratorOnClassAccessor8.js index f0917130521..e1fffdaec83 100644 --- a/tests/baselines/reference/decoratorOnClassAccessor8.js +++ b/tests/baselines/reference/decoratorOnClassAccessor8.js @@ -50,7 +50,7 @@ var A = /** @class */ (function () { }); __decorate([ dec, - __metadata("design:type", Object), + __metadata("design:type", Number), __metadata("design:paramtypes", [Number]) ], A.prototype, "x", null); return A; @@ -98,7 +98,7 @@ var D = /** @class */ (function () { }); __decorate([ dec, - __metadata("design:type", Object), + __metadata("design:type", Number), __metadata("design:paramtypes", [Number]) ], D.prototype, "x", null); return D; diff --git a/tests/baselines/reference/targetEs6DecoratorMetadataImportNotElided.js b/tests/baselines/reference/targetEs6DecoratorMetadataImportNotElided.js new file mode 100644 index 00000000000..b2126326793 --- /dev/null +++ b/tests/baselines/reference/targetEs6DecoratorMetadataImportNotElided.js @@ -0,0 +1,54 @@ +//// [tests/cases/compiler/targetEs6DecoratorMetadataImportNotElided.ts] //// + +//// [deps.ts] +export function Input(): any { } +export class TemplateRef { } + +//// [index.ts] +import { Input, TemplateRef } from './deps'; + +export class MyComponent { + _ref: TemplateRef; + + @Input() + get ref() { return this._ref; } + set ref(value: TemplateRef) { this._ref = value; } +} + + +//// [deps.js] +export function Input() { } +var TemplateRef = /** @class */ (function () { + function TemplateRef() { + } + return TemplateRef; +}()); +export { TemplateRef }; +//// [index.js] +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); +}; +import { Input, TemplateRef } from './deps'; +var MyComponent = /** @class */ (function () { + function MyComponent() { + } + Object.defineProperty(MyComponent.prototype, "ref", { + get: function () { return this._ref; }, + set: function (value) { this._ref = value; }, + enumerable: true, + configurable: true + }); + __decorate([ + Input(), + __metadata("design:type", TemplateRef), + __metadata("design:paramtypes", [TemplateRef]) + ], MyComponent.prototype, "ref", null); + return MyComponent; +}()); +export { MyComponent }; diff --git a/tests/baselines/reference/targetEs6DecoratorMetadataImportNotElided.symbols b/tests/baselines/reference/targetEs6DecoratorMetadataImportNotElided.symbols new file mode 100644 index 00000000000..9fe0ee6e0f3 --- /dev/null +++ b/tests/baselines/reference/targetEs6DecoratorMetadataImportNotElided.symbols @@ -0,0 +1,38 @@ +=== tests/cases/compiler/deps.ts === +export function Input(): any { } +>Input : Symbol(Input, Decl(deps.ts, 0, 0)) + +export class TemplateRef { } +>TemplateRef : Symbol(TemplateRef, Decl(deps.ts, 0, 32)) + +=== tests/cases/compiler/index.ts === +import { Input, TemplateRef } from './deps'; +>Input : Symbol(Input, Decl(index.ts, 0, 8)) +>TemplateRef : Symbol(TemplateRef, Decl(index.ts, 0, 15)) + +export class MyComponent { +>MyComponent : Symbol(MyComponent, Decl(index.ts, 0, 44)) + + _ref: TemplateRef; +>_ref : Symbol(MyComponent._ref, Decl(index.ts, 2, 26)) +>TemplateRef : Symbol(TemplateRef, Decl(index.ts, 0, 15)) + + @Input() +>Input : Symbol(Input, Decl(index.ts, 0, 8)) + + get ref() { return this._ref; } +>ref : Symbol(MyComponent.ref, Decl(index.ts, 3, 22), Decl(index.ts, 6, 35)) +>this._ref : Symbol(MyComponent._ref, Decl(index.ts, 2, 26)) +>this : Symbol(MyComponent, Decl(index.ts, 0, 44)) +>_ref : Symbol(MyComponent._ref, Decl(index.ts, 2, 26)) + + set ref(value: TemplateRef) { this._ref = value; } +>ref : Symbol(MyComponent.ref, Decl(index.ts, 3, 22), Decl(index.ts, 6, 35)) +>value : Symbol(value, Decl(index.ts, 7, 12)) +>TemplateRef : Symbol(TemplateRef, Decl(index.ts, 0, 15)) +>this._ref : Symbol(MyComponent._ref, Decl(index.ts, 2, 26)) +>this : Symbol(MyComponent, Decl(index.ts, 0, 44)) +>_ref : Symbol(MyComponent._ref, Decl(index.ts, 2, 26)) +>value : Symbol(value, Decl(index.ts, 7, 12)) +} + diff --git a/tests/baselines/reference/targetEs6DecoratorMetadataImportNotElided.types b/tests/baselines/reference/targetEs6DecoratorMetadataImportNotElided.types new file mode 100644 index 00000000000..44fbbd8621d --- /dev/null +++ b/tests/baselines/reference/targetEs6DecoratorMetadataImportNotElided.types @@ -0,0 +1,40 @@ +=== tests/cases/compiler/deps.ts === +export function Input(): any { } +>Input : () => any + +export class TemplateRef { } +>TemplateRef : TemplateRef + +=== tests/cases/compiler/index.ts === +import { Input, TemplateRef } from './deps'; +>Input : () => any +>TemplateRef : typeof TemplateRef + +export class MyComponent { +>MyComponent : MyComponent + + _ref: TemplateRef; +>_ref : TemplateRef +>TemplateRef : TemplateRef + + @Input() +>Input() : any +>Input : () => any + + get ref() { return this._ref; } +>ref : TemplateRef +>this._ref : TemplateRef +>this : this +>_ref : TemplateRef + + set ref(value: TemplateRef) { this._ref = value; } +>ref : TemplateRef +>value : TemplateRef +>TemplateRef : TemplateRef +>this._ref = value : TemplateRef +>this._ref : TemplateRef +>this : this +>_ref : TemplateRef +>value : TemplateRef +} + diff --git a/tests/cases/compiler/targetEs6DecoratorMetadataImportNotElided.ts b/tests/cases/compiler/targetEs6DecoratorMetadataImportNotElided.ts new file mode 100644 index 00000000000..16629f25879 --- /dev/null +++ b/tests/cases/compiler/targetEs6DecoratorMetadataImportNotElided.ts @@ -0,0 +1,18 @@ +// @module: es6 +// @target: es5 +// @emitDecoratorMetadata: true +// @experimentalDecorators: true +// @filename: deps.ts +export function Input(): any { } +export class TemplateRef { } + +// @filename: index.ts +import { Input, TemplateRef } from './deps'; + +export class MyComponent { + _ref: TemplateRef; + + @Input() + get ref() { return this._ref; } + set ref(value: TemplateRef) { this._ref = value; } +}