diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index aa677c911b874..e823695093cc0 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -846,7 +846,12 @@ namespace ts { const location = moveRangePastDecorators(node); const classAlias = getClassAliasIfNeeded(node); - const declName = factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true); + + // When we transform to ES5/3 this will be moved inside an IIFE and should reference the name + // without any block-scoped variable collision handling + const declName = languageVersion <= ScriptTarget.ES2015 ? + factory.getInternalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true) : + factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true); // ... = class ${name} ${heritageClauses} { // ${members} @@ -1256,7 +1261,12 @@ namespace ts { } const classAlias = classAliases && classAliases[getOriginalNodeId(node)]; - const localName = factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true); + + // When we transform to ES5/3 this will be moved inside an IIFE and should reference the name + // without any block-scoped variable collision handling + const localName = languageVersion <= ScriptTarget.ES2015 ? + factory.getInternalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true) : + factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true); const decorate = emitHelpers().createDecorateHelper(decoratorExpressions, localName); const expression = factory.createAssignment(localName, classAlias ? factory.createAssignment(classAlias, decorate) : decorate); setEmitFlags(expression, EmitFlags.NoComments); diff --git a/tests/baselines/reference/decoratedBlockScopedClass1.js b/tests/baselines/reference/decoratedBlockScopedClass1.js new file mode 100644 index 0000000000000..dc2b92da3b93d --- /dev/null +++ b/tests/baselines/reference/decoratedBlockScopedClass1.js @@ -0,0 +1,38 @@ +//// [a.ts] +function decorator() { + return (target: new (...args: any[]) => any) => {} +} + +@decorator() +class Foo { + public static func(): Foo { + return new Foo(); + } +} +Foo.func(); + + +//// [a.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; +}; +function decorator() { + return function (target) { }; +} +var Foo = /** @class */ (function () { + function Foo() { + } + Foo_1 = Foo; + Foo.func = function () { + return new Foo_1(); + }; + var Foo_1; + Foo = Foo_1 = __decorate([ + decorator() + ], Foo); + return Foo; +}()); +Foo.func(); diff --git a/tests/baselines/reference/decoratedBlockScopedClass1.symbols b/tests/baselines/reference/decoratedBlockScopedClass1.symbols new file mode 100644 index 0000000000000..2d90c8fe77a54 --- /dev/null +++ b/tests/baselines/reference/decoratedBlockScopedClass1.symbols @@ -0,0 +1,28 @@ +=== tests/cases/conformance/decorators/class/a.ts === +function decorator() { +>decorator : Symbol(decorator, Decl(a.ts, 0, 0)) + + return (target: new (...args: any[]) => any) => {} +>target : Symbol(target, Decl(a.ts, 1, 12)) +>args : Symbol(args, Decl(a.ts, 1, 25)) +} + +@decorator() +>decorator : Symbol(decorator, Decl(a.ts, 0, 0)) + +class Foo { +>Foo : Symbol(Foo, Decl(a.ts, 2, 1)) + + public static func(): Foo { +>func : Symbol(Foo.func, Decl(a.ts, 5, 11)) +>Foo : Symbol(Foo, Decl(a.ts, 2, 1)) + + return new Foo(); +>Foo : Symbol(Foo, Decl(a.ts, 2, 1)) + } +} +Foo.func(); +>Foo.func : Symbol(Foo.func, Decl(a.ts, 5, 11)) +>Foo : Symbol(Foo, Decl(a.ts, 2, 1)) +>func : Symbol(Foo.func, Decl(a.ts, 5, 11)) + diff --git a/tests/baselines/reference/decoratedBlockScopedClass1.types b/tests/baselines/reference/decoratedBlockScopedClass1.types new file mode 100644 index 0000000000000..f51de5f6f0145 --- /dev/null +++ b/tests/baselines/reference/decoratedBlockScopedClass1.types @@ -0,0 +1,31 @@ +=== tests/cases/conformance/decorators/class/a.ts === +function decorator() { +>decorator : () => (target: new (...args: any[]) => any) => void + + return (target: new (...args: any[]) => any) => {} +>(target: new (...args: any[]) => any) => {} : (target: new (...args: any[]) => any) => void +>target : new (...args: any[]) => any +>args : any[] +} + +@decorator() +>decorator() : (target: new (...args: any[]) => any) => void +>decorator : () => (target: new (...args: any[]) => any) => void + +class Foo { +>Foo : Foo + + public static func(): Foo { +>func : () => Foo + + return new Foo(); +>new Foo() : Foo +>Foo : typeof Foo + } +} +Foo.func(); +>Foo.func() : Foo +>Foo.func : () => Foo +>Foo : typeof Foo +>func : () => Foo + diff --git a/tests/baselines/reference/decoratedBlockScopedClass2.js b/tests/baselines/reference/decoratedBlockScopedClass2.js new file mode 100644 index 0000000000000..9b23dfc7ec434 --- /dev/null +++ b/tests/baselines/reference/decoratedBlockScopedClass2.js @@ -0,0 +1,44 @@ +//// [a.ts] +function decorator() { + return (target: new (...args: any[]) => any) => {} +} + +try { + @decorator() + class Foo { + public static func(): Foo { + return new Foo(); + } + } + Foo.func(); +} +catch (e) {} + + +//// [a.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; +}; +function decorator() { + return function (target) { }; +} +try { + var Foo_1 = /** @class */ (function () { + function Foo() { + } + Foo_2 = Foo; + Foo.func = function () { + return new Foo_2(); + }; + var Foo_2; + Foo = Foo_2 = __decorate([ + decorator() + ], Foo); + return Foo; + }()); + Foo_1.func(); +} +catch (e) { } diff --git a/tests/baselines/reference/decoratedBlockScopedClass2.symbols b/tests/baselines/reference/decoratedBlockScopedClass2.symbols new file mode 100644 index 0000000000000..b64af9e490b4d --- /dev/null +++ b/tests/baselines/reference/decoratedBlockScopedClass2.symbols @@ -0,0 +1,32 @@ +=== tests/cases/conformance/decorators/class/a.ts === +function decorator() { +>decorator : Symbol(decorator, Decl(a.ts, 0, 0)) + + return (target: new (...args: any[]) => any) => {} +>target : Symbol(target, Decl(a.ts, 1, 12)) +>args : Symbol(args, Decl(a.ts, 1, 25)) +} + +try { + @decorator() +>decorator : Symbol(decorator, Decl(a.ts, 0, 0)) + + class Foo { +>Foo : Symbol(Foo, Decl(a.ts, 4, 5)) + + public static func(): Foo { +>func : Symbol(Foo.func, Decl(a.ts, 6, 15)) +>Foo : Symbol(Foo, Decl(a.ts, 4, 5)) + + return new Foo(); +>Foo : Symbol(Foo, Decl(a.ts, 4, 5)) + } + } + Foo.func(); +>Foo.func : Symbol(Foo.func, Decl(a.ts, 6, 15)) +>Foo : Symbol(Foo, Decl(a.ts, 4, 5)) +>func : Symbol(Foo.func, Decl(a.ts, 6, 15)) +} +catch (e) {} +>e : Symbol(e, Decl(a.ts, 13, 7)) + diff --git a/tests/baselines/reference/decoratedBlockScopedClass2.types b/tests/baselines/reference/decoratedBlockScopedClass2.types new file mode 100644 index 0000000000000..9ce4353b0bc8e --- /dev/null +++ b/tests/baselines/reference/decoratedBlockScopedClass2.types @@ -0,0 +1,35 @@ +=== tests/cases/conformance/decorators/class/a.ts === +function decorator() { +>decorator : () => (target: new (...args: any[]) => any) => void + + return (target: new (...args: any[]) => any) => {} +>(target: new (...args: any[]) => any) => {} : (target: new (...args: any[]) => any) => void +>target : new (...args: any[]) => any +>args : any[] +} + +try { + @decorator() +>decorator() : (target: new (...args: any[]) => any) => void +>decorator : () => (target: new (...args: any[]) => any) => void + + class Foo { +>Foo : Foo + + public static func(): Foo { +>func : () => Foo + + return new Foo(); +>new Foo() : Foo +>Foo : typeof Foo + } + } + Foo.func(); +>Foo.func() : Foo +>Foo.func : () => Foo +>Foo : typeof Foo +>func : () => Foo +} +catch (e) {} +>e : any + diff --git a/tests/baselines/reference/decoratedBlockScopedClass3.js b/tests/baselines/reference/decoratedBlockScopedClass3.js new file mode 100644 index 0000000000000..c0ff1ceb85394 --- /dev/null +++ b/tests/baselines/reference/decoratedBlockScopedClass3.js @@ -0,0 +1,66 @@ +//// [a.ts] +function decorator() { + return (target: new (...args: any[]) => any) => {} +} + +@decorator() +class Foo { + public static func(): Foo { + return new Foo(); + } +} +Foo.func(); + +try { + @decorator() + class Foo { + public static func(): Foo { + return new Foo(); + } + } + Foo.func(); +} +catch (e) {} + + +//// [a.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; +}; +function decorator() { + return function (target) { }; +} +var Foo = /** @class */ (function () { + function Foo() { + } + Foo_1 = Foo; + Foo.func = function () { + return new Foo_1(); + }; + var Foo_1; + Foo = Foo_1 = __decorate([ + decorator() + ], Foo); + return Foo; +}()); +Foo.func(); +try { + var Foo_2 = /** @class */ (function () { + function Foo() { + } + Foo_3 = Foo; + Foo.func = function () { + return new Foo_3(); + }; + var Foo_3; + Foo = Foo_3 = __decorate([ + decorator() + ], Foo); + return Foo; + }()); + Foo_2.func(); +} +catch (e) { } diff --git a/tests/baselines/reference/decoratedBlockScopedClass3.symbols b/tests/baselines/reference/decoratedBlockScopedClass3.symbols new file mode 100644 index 0000000000000..026ca4a90d387 --- /dev/null +++ b/tests/baselines/reference/decoratedBlockScopedClass3.symbols @@ -0,0 +1,51 @@ +=== tests/cases/conformance/decorators/class/a.ts === +function decorator() { +>decorator : Symbol(decorator, Decl(a.ts, 0, 0)) + + return (target: new (...args: any[]) => any) => {} +>target : Symbol(target, Decl(a.ts, 1, 12)) +>args : Symbol(args, Decl(a.ts, 1, 25)) +} + +@decorator() +>decorator : Symbol(decorator, Decl(a.ts, 0, 0)) + +class Foo { +>Foo : Symbol(Foo, Decl(a.ts, 2, 1)) + + public static func(): Foo { +>func : Symbol(Foo.func, Decl(a.ts, 5, 11)) +>Foo : Symbol(Foo, Decl(a.ts, 2, 1)) + + return new Foo(); +>Foo : Symbol(Foo, Decl(a.ts, 2, 1)) + } +} +Foo.func(); +>Foo.func : Symbol(Foo.func, Decl(a.ts, 5, 11)) +>Foo : Symbol(Foo, Decl(a.ts, 2, 1)) +>func : Symbol(Foo.func, Decl(a.ts, 5, 11)) + +try { + @decorator() +>decorator : Symbol(decorator, Decl(a.ts, 0, 0)) + + class Foo { +>Foo : Symbol(Foo, Decl(a.ts, 12, 5)) + + public static func(): Foo { +>func : Symbol(Foo.func, Decl(a.ts, 14, 15)) +>Foo : Symbol(Foo, Decl(a.ts, 12, 5)) + + return new Foo(); +>Foo : Symbol(Foo, Decl(a.ts, 12, 5)) + } + } + Foo.func(); +>Foo.func : Symbol(Foo.func, Decl(a.ts, 14, 15)) +>Foo : Symbol(Foo, Decl(a.ts, 12, 5)) +>func : Symbol(Foo.func, Decl(a.ts, 14, 15)) +} +catch (e) {} +>e : Symbol(e, Decl(a.ts, 21, 7)) + diff --git a/tests/baselines/reference/decoratedBlockScopedClass3.types b/tests/baselines/reference/decoratedBlockScopedClass3.types new file mode 100644 index 0000000000000..c7315101b9613 --- /dev/null +++ b/tests/baselines/reference/decoratedBlockScopedClass3.types @@ -0,0 +1,56 @@ +=== tests/cases/conformance/decorators/class/a.ts === +function decorator() { +>decorator : () => (target: new (...args: any[]) => any) => void + + return (target: new (...args: any[]) => any) => {} +>(target: new (...args: any[]) => any) => {} : (target: new (...args: any[]) => any) => void +>target : new (...args: any[]) => any +>args : any[] +} + +@decorator() +>decorator() : (target: new (...args: any[]) => any) => void +>decorator : () => (target: new (...args: any[]) => any) => void + +class Foo { +>Foo : Foo + + public static func(): Foo { +>func : () => Foo + + return new Foo(); +>new Foo() : Foo +>Foo : typeof Foo + } +} +Foo.func(); +>Foo.func() : Foo +>Foo.func : () => Foo +>Foo : typeof Foo +>func : () => Foo + +try { + @decorator() +>decorator() : (target: new (...args: any[]) => any) => void +>decorator : () => (target: new (...args: any[]) => any) => void + + class Foo { +>Foo : Foo + + public static func(): Foo { +>func : () => Foo + + return new Foo(); +>new Foo() : Foo +>Foo : typeof Foo + } + } + Foo.func(); +>Foo.func() : Foo +>Foo.func : () => Foo +>Foo : typeof Foo +>func : () => Foo +} +catch (e) {} +>e : any + diff --git a/tests/cases/conformance/decorators/class/decoratedBlockScopedClass1.ts b/tests/cases/conformance/decorators/class/decoratedBlockScopedClass1.ts new file mode 100644 index 0000000000000..521dd6a31c6aa --- /dev/null +++ b/tests/cases/conformance/decorators/class/decoratedBlockScopedClass1.ts @@ -0,0 +1,16 @@ +// @target: es5 +// @experimentaldecorators: true +// @emitDecoratorMetadata: true +// @filename: a.ts + +function decorator() { + return (target: new (...args: any[]) => any) => {} +} + +@decorator() +class Foo { + public static func(): Foo { + return new Foo(); + } +} +Foo.func(); diff --git a/tests/cases/conformance/decorators/class/decoratedBlockScopedClass2.ts b/tests/cases/conformance/decorators/class/decoratedBlockScopedClass2.ts new file mode 100644 index 0000000000000..7d8de6894f783 --- /dev/null +++ b/tests/cases/conformance/decorators/class/decoratedBlockScopedClass2.ts @@ -0,0 +1,19 @@ +// @target: es5 +// @experimentaldecorators: true +// @emitDecoratorMetadata: true +// @filename: a.ts + +function decorator() { + return (target: new (...args: any[]) => any) => {} +} + +try { + @decorator() + class Foo { + public static func(): Foo { + return new Foo(); + } + } + Foo.func(); +} +catch (e) {} diff --git a/tests/cases/conformance/decorators/class/decoratedBlockScopedClass3.ts b/tests/cases/conformance/decorators/class/decoratedBlockScopedClass3.ts new file mode 100644 index 0000000000000..48eebc559f87a --- /dev/null +++ b/tests/cases/conformance/decorators/class/decoratedBlockScopedClass3.ts @@ -0,0 +1,27 @@ +// @target: es5 +// @experimentaldecorators: true +// @emitDecoratorMetadata: true +// @filename: a.ts + +function decorator() { + return (target: new (...args: any[]) => any) => {} +} + +@decorator() +class Foo { + public static func(): Foo { + return new Foo(); + } +} +Foo.func(); + +try { + @decorator() + class Foo { + public static func(): Foo { + return new Foo(); + } + } + Foo.func(); +} +catch (e) {}