Skip to content

Commit fe23cc3

Browse files
committed
Merge pull request microsoft#6684 from Microsoft/fixDecoratedClassName
Fix ES6 decorated class double binding.
2 parents b037419 + 4835e43 commit fe23cc3

42 files changed

Lines changed: 776 additions & 86 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/compiler/checker.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7192,11 +7192,32 @@ namespace ts {
71927192
markAliasSymbolAsReferenced(symbol);
71937193
}
71947194

7195+
const localOrExportSymbol = getExportSymbolOfValueSymbolIfExported(symbol);
7196+
7197+
// Due to the emit for class decorators, any reference to the class from inside of the class body
7198+
// must instead be rewritten to point to a temporary variable to avoid issues with the double-bind
7199+
// behavior of class names in ES6.
7200+
if (languageVersion === ScriptTarget.ES6
7201+
&& localOrExportSymbol.flags & SymbolFlags.Class
7202+
&& localOrExportSymbol.valueDeclaration.kind === SyntaxKind.ClassDeclaration
7203+
&& nodeIsDecorated(localOrExportSymbol.valueDeclaration)) {
7204+
let container = getContainingClass(node);
7205+
while (container !== undefined) {
7206+
if (container === localOrExportSymbol.valueDeclaration && container.name !== node) {
7207+
getNodeLinks(container).flags |= NodeCheckFlags.ClassWithBodyScopedClassBinding;
7208+
getNodeLinks(node).flags |= NodeCheckFlags.BodyScopedClassBinding;
7209+
break;
7210+
}
7211+
7212+
container = getContainingClass(container);
7213+
}
7214+
}
7215+
71957216
checkCollisionWithCapturedSuperVariable(node, node);
71967217
checkCollisionWithCapturedThisVariable(node, node);
71977218
checkNestedBlockScopedBinding(node, symbol);
71987219

7199-
return getNarrowedTypeOfSymbol(getExportSymbolOfValueSymbolIfExported(symbol), node);
7220+
return getNarrowedTypeOfSymbol(localOrExportSymbol, node);
72007221
}
72017222

72027223
function isInsideFunction(node: Node, threshold: Node): boolean {
@@ -7238,7 +7259,7 @@ namespace ts {
72387259

72397260
if (containedInIterationStatement) {
72407261
if (usedInFunction) {
7241-
// mark iteration statement as containing block-scoped binding captured in some function
7262+
// mark iteration statement as containing block-scoped binding captured in some function
72427263
getNodeLinks(current).flags |= NodeCheckFlags.LoopWithCapturedBlockScopedBinding;
72437264
}
72447265
// set 'declared inside loop' bit on the block-scoped binding
@@ -15758,7 +15779,7 @@ namespace ts {
1575815779
// - binding is not top level - top level bindings never collide with anything
1575915780
// AND
1576015781
// - binding is not declared in loop, should be renamed to avoid name reuse across siblings
15761-
// let a, b
15782+
// let a, b
1576215783
// { let x = 1; a = () => x; }
1576315784
// { let x = 100; b = () => x; }
1576415785
// console.log(a()); // should print '1'

src/compiler/emitter.ts

Lines changed: 114 additions & 59 deletions
Large diffs are not rendered by default.

src/compiler/types.ts

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2054,23 +2054,23 @@ namespace ts {
20542054

20552055
/* @internal */
20562056
export const enum NodeCheckFlags {
2057-
TypeChecked = 0x00000001, // Node has been type checked
2058-
LexicalThis = 0x00000002, // Lexical 'this' reference
2059-
CaptureThis = 0x00000004, // Lexical 'this' used in body
2060-
SuperInstance = 0x00000100, // Instance 'super' reference
2061-
SuperStatic = 0x00000200, // Static 'super' reference
2062-
ContextChecked = 0x00000400, // Contextual types have been assigned
2063-
AsyncMethodWithSuper = 0x00000800, // An async method that reads a value from a member of 'super'.
2064-
AsyncMethodWithSuperBinding = 0x00001000, // An async method that assigns a value to a member of 'super'.
2065-
CaptureArguments = 0x00002000, // Lexical 'arguments' used in body (for async functions)
2066-
2067-
// Values for enum members have been computed, and any errors have been reported for them.
2068-
EnumValuesComputed = 0x00004000,
2069-
LexicalModuleMergesWithClass = 0x00008000, // Instantiated lexical module declaration is merged with a previous class declaration.
2070-
LoopWithCapturedBlockScopedBinding = 0x00010000, // Loop that contains block scoped variable captured in closure
2071-
CapturedBlockScopedBinding = 0x00020000, // Block-scoped binding that is captured in some function
2072-
BlockScopedBindingInLoop = 0x00040000, // Block-scoped binding with declaration nested inside iteration statement
2073-
HasSeenSuperCall = 0x00080000, // Set during the binding when encounter 'super'
2057+
TypeChecked = 0x00000001, // Node has been type checked
2058+
LexicalThis = 0x00000002, // Lexical 'this' reference
2059+
CaptureThis = 0x00000004, // Lexical 'this' used in body
2060+
SuperInstance = 0x00000100, // Instance 'super' reference
2061+
SuperStatic = 0x00000200, // Static 'super' reference
2062+
ContextChecked = 0x00000400, // Contextual types have been assigned
2063+
AsyncMethodWithSuper = 0x00000800, // An async method that reads a value from a member of 'super'.
2064+
AsyncMethodWithSuperBinding = 0x00001000, // An async method that assigns a value to a member of 'super'.
2065+
CaptureArguments = 0x00002000, // Lexical 'arguments' used in body (for async functions)
2066+
EnumValuesComputed = 0x00004000, // Values for enum members have been computed, and any errors have been reported for them.
2067+
LexicalModuleMergesWithClass = 0x00008000, // Instantiated lexical module declaration is merged with a previous class declaration.
2068+
LoopWithCapturedBlockScopedBinding = 0x00010000, // Loop that contains block scoped variable captured in closure
2069+
CapturedBlockScopedBinding = 0x00020000, // Block-scoped binding that is captured in some function
2070+
BlockScopedBindingInLoop = 0x00040000, // Block-scoped binding with declaration nested inside iteration statement
2071+
HasSeenSuperCall = 0x00080000, // Set during the binding when encounter 'super'
2072+
ClassWithBodyScopedClassBinding = 0x00100000, // Decorated class that contains a binding to itself inside of the class body.
2073+
BodyScopedClassBinding = 0x00200000, // Binding to a decorated class inside of the class's body.
20742074
}
20752075

20762076
/* @internal */

tests/baselines/reference/decoratedClassFromExternalModule.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
1717
return c > 3 && r && Object.defineProperty(target, key, r), r;
1818
};
1919
function decorate(target) { }
20-
let Decorated = class {
20+
let Decorated = class Decorated {
2121
};
2222
Decorated = __decorate([
2323
decorate

tests/baselines/reference/decoratedDefaultExportsGetExportedAmd.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
2323
define(["require", "exports"], function (require, exports) {
2424
"use strict";
2525
var decorator;
26-
let Foo = class {
26+
let Foo = class Foo {
2727
};
2828
Foo = __decorate([
2929
decorator

tests/baselines/reference/decoratedDefaultExportsGetExportedCommonjs.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
2222
return c > 3 && r && Object.defineProperty(target, key, r), r;
2323
};
2424
var decorator;
25-
let Foo = class {
25+
let Foo = class Foo {
2626
};
2727
Foo = __decorate([
2828
decorator

tests/baselines/reference/decoratedDefaultExportsGetExportedSystem.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ System.register([], function(exports_1, context_1) {
2626
return {
2727
setters:[],
2828
execute: function() {
29-
let Foo = class {
29+
let Foo = class Foo {
3030
};
3131
Foo = __decorate([
3232
decorator

tests/baselines/reference/decoratedDefaultExportsGetExportedUmd.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
3030
})(function (require, exports) {
3131
"use strict";
3232
var decorator;
33-
let Foo = class {
33+
let Foo = class Foo {
3434
};
3535
Foo = __decorate([
3636
decorator
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//// [decoratorOnClass1.es6.ts]
2+
declare function dec<T>(target: T): T;
3+
4+
@dec
5+
class C {
6+
}
7+
8+
let c = new C();
9+
10+
//// [decoratorOnClass1.es6.js]
11+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
12+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
13+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
14+
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;
15+
return c > 3 && r && Object.defineProperty(target, key, r), r;
16+
};
17+
let C = class C {
18+
};
19+
C = __decorate([
20+
dec
21+
], C);
22+
let c = new C();
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
=== tests/cases/conformance/es6/decorators/class/decoratorOnClass1.es6.ts ===
2+
declare function dec<T>(target: T): T;
3+
>dec : Symbol(dec, Decl(decoratorOnClass1.es6.ts, 0, 0))
4+
>T : Symbol(T, Decl(decoratorOnClass1.es6.ts, 0, 21))
5+
>target : Symbol(target, Decl(decoratorOnClass1.es6.ts, 0, 24))
6+
>T : Symbol(T, Decl(decoratorOnClass1.es6.ts, 0, 21))
7+
>T : Symbol(T, Decl(decoratorOnClass1.es6.ts, 0, 21))
8+
9+
@dec
10+
>dec : Symbol(dec, Decl(decoratorOnClass1.es6.ts, 0, 0))
11+
12+
class C {
13+
>C : Symbol(C, Decl(decoratorOnClass1.es6.ts, 0, 38))
14+
}
15+
16+
let c = new C();
17+
>c : Symbol(c, Decl(decoratorOnClass1.es6.ts, 6, 3))
18+
>C : Symbol(C, Decl(decoratorOnClass1.es6.ts, 0, 38))
19+

0 commit comments

Comments
 (0)