Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7192,11 +7192,32 @@ namespace ts {
markAliasSymbolAsReferenced(symbol);
}

const localOrExportSymbol = getExportSymbolOfValueSymbolIfExported(symbol);

// Due to the emit for class decorators, any reference to the class from inside of the class body
// must instead be rewritten to point to a temporary variable to avoid issues with the double-bind
// behavior of class names in ES6.
if (languageVersion === ScriptTarget.ES6
&& localOrExportSymbol.flags & SymbolFlags.Class
&& localOrExportSymbol.valueDeclaration.kind === SyntaxKind.ClassDeclaration
&& nodeIsDecorated(localOrExportSymbol.valueDeclaration)) {
let container = getContainingClass(node);
while (container !== undefined) {
if (container === localOrExportSymbol.valueDeclaration && container.name !== node) {
getNodeLinks(container).flags |= NodeCheckFlags.ClassWithBodyScopedClassBinding;
getNodeLinks(node).flags |= NodeCheckFlags.BodyScopedClassBinding;
break;
}

container = getContainingClass(container);
}
}

checkCollisionWithCapturedSuperVariable(node, node);
checkCollisionWithCapturedThisVariable(node, node);
checkNestedBlockScopedBinding(node, symbol);

return getNarrowedTypeOfSymbol(getExportSymbolOfValueSymbolIfExported(symbol), node);
return getNarrowedTypeOfSymbol(localOrExportSymbol, node);
}

function isInsideFunction(node: Node, threshold: Node): boolean {
Expand Down Expand Up @@ -7238,7 +7259,7 @@ namespace ts {

if (containedInIterationStatement) {
if (usedInFunction) {
// mark iteration statement as containing block-scoped binding captured in some function
// mark iteration statement as containing block-scoped binding captured in some function
getNodeLinks(current).flags |= NodeCheckFlags.LoopWithCapturedBlockScopedBinding;
}
// set 'declared inside loop' bit on the block-scoped binding
Expand Down Expand Up @@ -15758,7 +15779,7 @@ namespace ts {
// - binding is not top level - top level bindings never collide with anything
// AND
// - binding is not declared in loop, should be renamed to avoid name reuse across siblings
// let a, b
// let a, b
// { let x = 1; a = () => x; }
// { let x = 100; b = () => x; }
// console.log(a()); // should print '1'
Expand Down
173 changes: 114 additions & 59 deletions src/compiler/emitter.ts

Large diffs are not rendered by default.

34 changes: 17 additions & 17 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2054,23 +2054,23 @@ namespace ts {

/* @internal */
export const enum NodeCheckFlags {
TypeChecked = 0x00000001, // Node has been type checked
LexicalThis = 0x00000002, // Lexical 'this' reference
CaptureThis = 0x00000004, // Lexical 'this' used in body
SuperInstance = 0x00000100, // Instance 'super' reference
SuperStatic = 0x00000200, // Static 'super' reference
ContextChecked = 0x00000400, // Contextual types have been assigned
AsyncMethodWithSuper = 0x00000800, // An async method that reads a value from a member of 'super'.
AsyncMethodWithSuperBinding = 0x00001000, // An async method that assigns a value to a member of 'super'.
CaptureArguments = 0x00002000, // Lexical 'arguments' used in body (for async functions)

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

/* @internal */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
function decorate(target) { }
let Decorated = class {
let Decorated = class Decorated {
};
Decorated = __decorate([
decorate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
define(["require", "exports"], function (require, exports) {
"use strict";
var decorator;
let Foo = class {
let Foo = class Foo {
};
Foo = __decorate([
decorator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var decorator;
let Foo = class {
let Foo = class Foo {
};
Foo = __decorate([
decorator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ System.register([], function(exports_1) {
return {
setters:[],
execute: function() {
let Foo = class {
let Foo = class Foo {
};
Foo = __decorate([
decorator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
})(function (require, exports) {
"use strict";
var decorator;
let Foo = class {
let Foo = class Foo {
};
Foo = __decorate([
decorator
Expand Down
22 changes: 22 additions & 0 deletions tests/baselines/reference/decoratorOnClass1.es6.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//// [decoratorOnClass1.es6.ts]
declare function dec<T>(target: T): T;

@dec
class C {
}

let c = new C();

//// [decoratorOnClass1.es6.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;
};
let C = class C {
};
C = __decorate([
dec
], C);
let c = new C();
19 changes: 19 additions & 0 deletions tests/baselines/reference/decoratorOnClass1.es6.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
=== tests/cases/conformance/es6/decorators/class/decoratorOnClass1.es6.ts ===
declare function dec<T>(target: T): T;
>dec : Symbol(dec, Decl(decoratorOnClass1.es6.ts, 0, 0))
>T : Symbol(T, Decl(decoratorOnClass1.es6.ts, 0, 21))
>target : Symbol(target, Decl(decoratorOnClass1.es6.ts, 0, 24))
>T : Symbol(T, Decl(decoratorOnClass1.es6.ts, 0, 21))
>T : Symbol(T, Decl(decoratorOnClass1.es6.ts, 0, 21))

@dec
>dec : Symbol(dec, Decl(decoratorOnClass1.es6.ts, 0, 0))

class C {
>C : Symbol(C, Decl(decoratorOnClass1.es6.ts, 0, 38))
}

let c = new C();
>c : Symbol(c, Decl(decoratorOnClass1.es6.ts, 6, 3))
>C : Symbol(C, Decl(decoratorOnClass1.es6.ts, 0, 38))

20 changes: 20 additions & 0 deletions tests/baselines/reference/decoratorOnClass1.es6.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
=== tests/cases/conformance/es6/decorators/class/decoratorOnClass1.es6.ts ===
declare function dec<T>(target: T): T;
>dec : <T>(target: T) => T
>T : T
>target : T
>T : T
>T : T

@dec
>dec : <T>(target: T) => T

class C {
>C : C
}

let c = new C();
>c : C
>new C() : C
>C : typeof C

22 changes: 22 additions & 0 deletions tests/baselines/reference/decoratorOnClass2.es6.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//// [decoratorOnClass2.es6.ts]
declare function dec<T>(target: T): T;

@dec
export class C {
}

let c = new C();

//// [decoratorOnClass2.es6.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;
};
export let C = class C {
};
C = __decorate([
dec
], C);
let c = new C();
19 changes: 19 additions & 0 deletions tests/baselines/reference/decoratorOnClass2.es6.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
=== tests/cases/conformance/es6/decorators/class/decoratorOnClass2.es6.ts ===
declare function dec<T>(target: T): T;
>dec : Symbol(dec, Decl(decoratorOnClass2.es6.ts, 0, 0))
>T : Symbol(T, Decl(decoratorOnClass2.es6.ts, 0, 21))
>target : Symbol(target, Decl(decoratorOnClass2.es6.ts, 0, 24))
>T : Symbol(T, Decl(decoratorOnClass2.es6.ts, 0, 21))
>T : Symbol(T, Decl(decoratorOnClass2.es6.ts, 0, 21))

@dec
>dec : Symbol(dec, Decl(decoratorOnClass2.es6.ts, 0, 0))

export class C {
>C : Symbol(C, Decl(decoratorOnClass2.es6.ts, 0, 38))
}

let c = new C();
>c : Symbol(c, Decl(decoratorOnClass2.es6.ts, 6, 3))
>C : Symbol(C, Decl(decoratorOnClass2.es6.ts, 0, 38))

20 changes: 20 additions & 0 deletions tests/baselines/reference/decoratorOnClass2.es6.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
=== tests/cases/conformance/es6/decorators/class/decoratorOnClass2.es6.ts ===
declare function dec<T>(target: T): T;
>dec : <T>(target: T) => T
>T : T
>target : T
>T : T
>T : T

@dec
>dec : <T>(target: T) => T

export class C {
>C : C
}

let c = new C();
>c : C
>new C() : C
>C : typeof C

23 changes: 23 additions & 0 deletions tests/baselines/reference/decoratorOnClass3.es6.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//// [decoratorOnClass3.es6.ts]
declare function dec<T>(target: T): T;

@dec
export default class C {
}

let c = new C();

//// [decoratorOnClass3.es6.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;
};
let C = class C {
};
C = __decorate([
dec
], C);
export default C;
let c = new C();
19 changes: 19 additions & 0 deletions tests/baselines/reference/decoratorOnClass3.es6.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
=== tests/cases/conformance/es6/decorators/class/decoratorOnClass3.es6.ts ===
declare function dec<T>(target: T): T;
>dec : Symbol(dec, Decl(decoratorOnClass3.es6.ts, 0, 0))
>T : Symbol(T, Decl(decoratorOnClass3.es6.ts, 0, 21))
>target : Symbol(target, Decl(decoratorOnClass3.es6.ts, 0, 24))
>T : Symbol(T, Decl(decoratorOnClass3.es6.ts, 0, 21))
>T : Symbol(T, Decl(decoratorOnClass3.es6.ts, 0, 21))

@dec
>dec : Symbol(dec, Decl(decoratorOnClass3.es6.ts, 0, 0))

export default class C {
>C : Symbol(C, Decl(decoratorOnClass3.es6.ts, 0, 38))
}

let c = new C();
>c : Symbol(c, Decl(decoratorOnClass3.es6.ts, 6, 3))
>C : Symbol(C, Decl(decoratorOnClass3.es6.ts, 0, 38))

20 changes: 20 additions & 0 deletions tests/baselines/reference/decoratorOnClass3.es6.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
=== tests/cases/conformance/es6/decorators/class/decoratorOnClass3.es6.ts ===
declare function dec<T>(target: T): T;
>dec : <T>(target: T) => T
>T : T
>target : T
>T : T
>T : T

@dec
>dec : <T>(target: T) => T

export default class C {
>C : C
}

let c = new C();
>c : C
>new C() : C
>C : typeof C

20 changes: 20 additions & 0 deletions tests/baselines/reference/decoratorOnClass4.es6.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//// [decoratorOnClass4.es6.ts]
declare function dec<T>(target: T): T;

@dec
export default class {
}

//// [decoratorOnClass4.es6.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;
};
let default_1 = class {
};
default_1 = __decorate([
dec
], default_1);
export default default_1;
13 changes: 13 additions & 0 deletions tests/baselines/reference/decoratorOnClass4.es6.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
=== tests/cases/conformance/es6/decorators/class/decoratorOnClass4.es6.ts ===
declare function dec<T>(target: T): T;
>dec : Symbol(dec, Decl(decoratorOnClass4.es6.ts, 0, 0))
>T : Symbol(T, Decl(decoratorOnClass4.es6.ts, 0, 21))
>target : Symbol(target, Decl(decoratorOnClass4.es6.ts, 0, 24))
>T : Symbol(T, Decl(decoratorOnClass4.es6.ts, 0, 21))
>T : Symbol(T, Decl(decoratorOnClass4.es6.ts, 0, 21))

@dec
>dec : Symbol(dec, Decl(decoratorOnClass4.es6.ts, 0, 0))

export default class {
}
13 changes: 13 additions & 0 deletions tests/baselines/reference/decoratorOnClass4.es6.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
=== tests/cases/conformance/es6/decorators/class/decoratorOnClass4.es6.ts ===
declare function dec<T>(target: T): T;
>dec : <T>(target: T) => T
>T : T
>target : T
>T : T
>T : T

@dec
>dec : <T>(target: T) => T

export default class {
}
Loading