Skip to content

Commit 463d1f5

Browse files
committed
Creates a class body scoped alias to the class to avoid class name double binding.
Fixes #5386.
1 parent c7a3cb6 commit 463d1f5

Some content is hidden

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

42 files changed

+771
-71
lines changed

src/compiler/checker.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7165,11 +7165,33 @@ namespace ts {
71657165
markAliasSymbolAsReferenced(symbol);
71667166
}
71677167

7168+
const localSymbol = getExportSymbolOfValueSymbolIfExported(symbol);
7169+
7170+
// Due to the emit for class decorators, any reference to the class from inside of the class body
7171+
// must instead be rewritten to point to a temporary variable to avoid issues with the double-bind
7172+
// behavior of class names in ES6.
7173+
if (languageVersion === ScriptTarget.ES6
7174+
&& localSymbol
7175+
&& localSymbol.valueDeclaration
7176+
&& localSymbol.valueDeclaration.kind === SyntaxKind.ClassDeclaration
7177+
&& nodeIsDecorated(localSymbol.valueDeclaration)) {
7178+
let container = getContainingClass(node);
7179+
while (container !== undefined) {
7180+
if (container === localSymbol.valueDeclaration && container.name !== node) {
7181+
getNodeLinks(container).flags |= NodeCheckFlags.ClassWithBodyScopedClassBinding;
7182+
getNodeLinks(node).flags |= NodeCheckFlags.BodyScopedClassBinding;
7183+
break;
7184+
}
7185+
7186+
container = getContainingClass(container);
7187+
}
7188+
}
7189+
71687190
checkCollisionWithCapturedSuperVariable(node, node);
71697191
checkCollisionWithCapturedThisVariable(node, node);
71707192
checkNestedBlockScopedBinding(node, symbol);
71717193

7172-
return getNarrowedTypeOfSymbol(getExportSymbolOfValueSymbolIfExported(symbol), node);
7194+
return getNarrowedTypeOfSymbol(localSymbol, node);
71737195
}
71747196

71757197
function isInsideFunction(node: Node, threshold: Node): boolean {
@@ -7211,7 +7233,7 @@ namespace ts {
72117233

72127234
if (containedInIterationStatement) {
72137235
if (usedInFunction) {
7214-
// mark iteration statement as containing block-scoped binding captured in some function
7236+
// mark iteration statement as containing block-scoped binding captured in some function
72157237
getNodeLinks(current).flags |= NodeCheckFlags.LoopWithCapturedBlockScopedBinding;
72167238
}
72177239
// set 'declared inside loop' bit on the block-scoped binding
@@ -15714,7 +15736,7 @@ namespace ts {
1571415736
// - binding is not top level - top level bindings never collide with anything
1571515737
// AND
1571615738
// - binding is not declared in loop, should be renamed to avoid name reuse across siblings
15717-
// let a, b
15739+
// let a, b
1571815740
// { let x = 1; a = () => x; }
1571915741
// { let x = 100; b = () => x; }
1572015742
// console.log(a()); // should print '1'

src/compiler/emitter.ts

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

src/compiler/types.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2066,9 +2066,11 @@ namespace ts {
20662066
EnumValuesComputed = 0x00004000,
20672067
LexicalModuleMergesWithClass = 0x00008000, // Instantiated lexical module declaration is merged with a previous class declaration.
20682068
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
2069+
CapturedBlockScopedBinding = 0x00020000, // Block-scoped binding that is captured in some function
2070+
BlockScopedBindingInLoop = 0x00040000, // Block-scoped binding with declaration nested inside iteration statement
20712071
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.
20722074
}
20732075

20742076
/* @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+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
=== tests/cases/conformance/es6/decorators/class/decoratorOnClass1.es6.ts ===
2+
declare function dec<T>(target: T): T;
3+
>dec : <T>(target: T) => T
4+
>T : T
5+
>target : T
6+
>T : T
7+
>T : T
8+
9+
@dec
10+
>dec : <T>(target: T) => T
11+
12+
class C {
13+
>C : C
14+
}
15+
16+
let c = new C();
17+
>c : C
18+
>new C() : C
19+
>C : typeof C
20+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//// [decoratorOnClass2.es6.ts]
2+
declare function dec<T>(target: T): T;
3+
4+
@dec
5+
export class C {
6+
}
7+
8+
let c = new C();
9+
10+
//// [decoratorOnClass2.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+
export 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/decoratorOnClass2.es6.ts ===
2+
declare function dec<T>(target: T): T;
3+
>dec : Symbol(dec, Decl(decoratorOnClass2.es6.ts, 0, 0))
4+
>T : Symbol(T, Decl(decoratorOnClass2.es6.ts, 0, 21))
5+
>target : Symbol(target, Decl(decoratorOnClass2.es6.ts, 0, 24))
6+
>T : Symbol(T, Decl(decoratorOnClass2.es6.ts, 0, 21))
7+
>T : Symbol(T, Decl(decoratorOnClass2.es6.ts, 0, 21))
8+
9+
@dec
10+
>dec : Symbol(dec, Decl(decoratorOnClass2.es6.ts, 0, 0))
11+
12+
export class C {
13+
>C : Symbol(C, Decl(decoratorOnClass2.es6.ts, 0, 38))
14+
}
15+
16+
let c = new C();
17+
>c : Symbol(c, Decl(decoratorOnClass2.es6.ts, 6, 3))
18+
>C : Symbol(C, Decl(decoratorOnClass2.es6.ts, 0, 38))
19+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
=== tests/cases/conformance/es6/decorators/class/decoratorOnClass2.es6.ts ===
2+
declare function dec<T>(target: T): T;
3+
>dec : <T>(target: T) => T
4+
>T : T
5+
>target : T
6+
>T : T
7+
>T : T
8+
9+
@dec
10+
>dec : <T>(target: T) => T
11+
12+
export class C {
13+
>C : C
14+
}
15+
16+
let c = new C();
17+
>c : C
18+
>new C() : C
19+
>C : typeof C
20+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//// [decoratorOnClass3.es6.ts]
2+
declare function dec<T>(target: T): T;
3+
4+
@dec
5+
export default class C {
6+
}
7+
8+
let c = new C();
9+
10+
//// [decoratorOnClass3.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+
export default C;
23+
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/decoratorOnClass3.es6.ts ===
2+
declare function dec<T>(target: T): T;
3+
>dec : Symbol(dec, Decl(decoratorOnClass3.es6.ts, 0, 0))
4+
>T : Symbol(T, Decl(decoratorOnClass3.es6.ts, 0, 21))
5+
>target : Symbol(target, Decl(decoratorOnClass3.es6.ts, 0, 24))
6+
>T : Symbol(T, Decl(decoratorOnClass3.es6.ts, 0, 21))
7+
>T : Symbol(T, Decl(decoratorOnClass3.es6.ts, 0, 21))
8+
9+
@dec
10+
>dec : Symbol(dec, Decl(decoratorOnClass3.es6.ts, 0, 0))
11+
12+
export default class C {
13+
>C : Symbol(C, Decl(decoratorOnClass3.es6.ts, 0, 38))
14+
}
15+
16+
let c = new C();
17+
>c : Symbol(c, Decl(decoratorOnClass3.es6.ts, 6, 3))
18+
>C : Symbol(C, Decl(decoratorOnClass3.es6.ts, 0, 38))
19+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
=== tests/cases/conformance/es6/decorators/class/decoratorOnClass3.es6.ts ===
2+
declare function dec<T>(target: T): T;
3+
>dec : <T>(target: T) => T
4+
>T : T
5+
>target : T
6+
>T : T
7+
>T : T
8+
9+
@dec
10+
>dec : <T>(target: T) => T
11+
12+
export default class C {
13+
>C : C
14+
}
15+
16+
let c = new C();
17+
>c : C
18+
>new C() : C
19+
>C : typeof C
20+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//// [decoratorOnClass4.es6.ts]
2+
declare function dec<T>(target: T): T;
3+
4+
@dec
5+
export default class {
6+
}
7+
8+
//// [decoratorOnClass4.es6.js]
9+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
10+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
11+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
12+
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;
13+
return c > 3 && r && Object.defineProperty(target, key, r), r;
14+
};
15+
let default_1 = class {
16+
};
17+
default_1 = __decorate([
18+
dec
19+
], default_1);
20+
export default default_1;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
=== tests/cases/conformance/es6/decorators/class/decoratorOnClass4.es6.ts ===
2+
declare function dec<T>(target: T): T;
3+
>dec : Symbol(dec, Decl(decoratorOnClass4.es6.ts, 0, 0))
4+
>T : Symbol(T, Decl(decoratorOnClass4.es6.ts, 0, 21))
5+
>target : Symbol(target, Decl(decoratorOnClass4.es6.ts, 0, 24))
6+
>T : Symbol(T, Decl(decoratorOnClass4.es6.ts, 0, 21))
7+
>T : Symbol(T, Decl(decoratorOnClass4.es6.ts, 0, 21))
8+
9+
@dec
10+
>dec : Symbol(dec, Decl(decoratorOnClass4.es6.ts, 0, 0))
11+
12+
export default class {
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
=== tests/cases/conformance/es6/decorators/class/decoratorOnClass4.es6.ts ===
2+
declare function dec<T>(target: T): T;
3+
>dec : <T>(target: T) => T
4+
>T : T
5+
>target : T
6+
>T : T
7+
>T : T
8+
9+
@dec
10+
>dec : <T>(target: T) => T
11+
12+
export default class {
13+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//// [decoratorOnClass5.es6.ts]
2+
declare function dec<T>(target: T): T;
3+
4+
@dec
5+
class C {
6+
static x() { return C.y; }
7+
static y = 1;
8+
}
9+
10+
let c = new C();
11+
12+
//// [decoratorOnClass5.es6.js]
13+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
14+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
15+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
16+
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;
17+
return c > 3 && r && Object.defineProperty(target, key, r), r;
18+
};
19+
let C_1;
20+
let C = C_1 = class C {
21+
static x() { return C_1.y; }
22+
};
23+
C.y = 1;
24+
C = C_1 = __decorate([
25+
dec
26+
], C);
27+
let c = new C();

0 commit comments

Comments
 (0)