Skip to content

Commit 4835e43

Browse files
committed
Merge branch 'master' into fixDecoratedClassName
2 parents 0978639 + e954929 commit 4835e43

59 files changed

Lines changed: 918 additions & 81 deletions

File tree

Some content is hidden

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

src/compiler/binder.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1462,7 +1462,7 @@ namespace ts {
14621462
function bindCallExpression(node: CallExpression) {
14631463
// We're only inspecting call expressions to detect CommonJS modules, so we can skip
14641464
// this check if we've already seen the module indicator
1465-
if (!file.commonJsModuleIndicator && isRequireCall(node)) {
1465+
if (!file.commonJsModuleIndicator && isRequireCall(node, /*checkArgumentIsStringLiteral*/false)) {
14661466
setCommonJsModuleIndicator(node);
14671467
}
14681468
}

src/compiler/checker.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7288,6 +7288,14 @@ namespace ts {
72887288
let container = getThisContainer(node, /* includeArrowFunctions */ true);
72897289
let needToCaptureLexicalThis = false;
72907290

7291+
if (container.kind === SyntaxKind.Constructor) {
7292+
const baseTypeNode = getClassExtendsHeritageClauseElement(<ClassLikeDeclaration>container.parent);
7293+
if (baseTypeNode && !(getNodeCheckFlags(container) & NodeCheckFlags.HasSeenSuperCall)) {
7294+
// In ES6, super inside constructor of class-declaration has to precede "this" accessing
7295+
error(node, Diagnostics.super_must_be_called_before_accessing_this_in_the_constructor_of_a_derived_class);
7296+
}
7297+
}
7298+
72917299
// Now skip arrow functions to get the "real" owner of 'this'.
72927300
if (container.kind === SyntaxKind.ArrowFunction) {
72937301
container = getThisContainer(container, /* includeArrowFunctions */ false);
@@ -10234,6 +10242,11 @@ namespace ts {
1023410242

1023510243
const signature = getResolvedSignature(node);
1023610244
if (node.expression.kind === SyntaxKind.SuperKeyword) {
10245+
const containgFunction = getContainingFunction(node.expression);
10246+
10247+
if (containgFunction && containgFunction.kind === SyntaxKind.Constructor) {
10248+
getNodeLinks(containgFunction).flags |= NodeCheckFlags.HasSeenSuperCall;
10249+
}
1023710250
return voidType;
1023810251
}
1023910252
if (node.kind === SyntaxKind.NewExpression) {
@@ -10260,7 +10273,7 @@ namespace ts {
1026010273
}
1026110274

1026210275
// In JavaScript files, calls to any identifier 'require' are treated as external module imports
10263-
if (isInJavaScriptFile(node) && isRequireCall(node)) {
10276+
if (isInJavaScriptFile(node) && isRequireCall(node, /*checkArgumentIsStringLiteral*/true)) {
1026410277
return resolveExternalModuleTypeByLiteral(<StringLiteral>node.arguments[0]);
1026510278
}
1026610279

@@ -11851,10 +11864,6 @@ namespace ts {
1185111864
if (!superCallStatement) {
1185211865
error(node, Diagnostics.A_super_call_must_be_the_first_statement_in_the_constructor_when_a_class_contains_initialized_properties_or_has_parameter_properties);
1185311866
}
11854-
else {
11855-
// In such a required super call, it is a compile-time error for argument expressions to reference this.
11856-
markThisReferencesAsErrors(superCallStatement.expression);
11857-
}
1185811867
}
1185911868
}
1186011869
else if (baseConstructorType !== nullType) {

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2771,5 +2771,9 @@
27712771
"JSX element '{0}' has no corresponding closing tag.": {
27722772
"category": "Error",
27732773
"code": 17008
2774+
},
2775+
"'super' must be called before accessing 'this' in the constructor of a derived class.": {
2776+
"category": "Error",
2777+
"code": 17009
27742778
}
27752779
}

src/compiler/program.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1328,7 +1328,7 @@ namespace ts {
13281328
}
13291329

13301330
function collectRequireCalls(node: Node): void {
1331-
if (isRequireCall(node)) {
1331+
if (isRequireCall(node, /*checkArgumentIsStringLiteral*/true)) {
13321332
(imports || (imports = [])).push(<StringLiteral>(<CallExpression>node).arguments[0]);
13331333
}
13341334
else {

src/compiler/types.ts

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2054,24 +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-
ClassWithBodyScopedClassBinding = 0x00080000, // Decorated class that contains a binding to itself inside of the class body.
2074-
BodyScopedClassBinding = 0x00100000, // Binding to a decorated class inside of the class's body.
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.
20752074
}
20762075

20772076
/* @internal */

src/compiler/utilities.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,12 +1086,14 @@ namespace ts {
10861086
* exactly one argument.
10871087
* This function does not test if the node is in a JavaScript file or not.
10881088
*/
1089-
export function isRequireCall(expression: Node): expression is CallExpression {
1089+
export function isRequireCall(expression: Node, checkArgumentIsStringLiteral: boolean): expression is CallExpression {
10901090
// of the form 'require("name")'
1091-
return expression.kind === SyntaxKind.CallExpression &&
1092-
(<CallExpression>expression).expression.kind === SyntaxKind.Identifier &&
1093-
(<Identifier>(<CallExpression>expression).expression).text === "require" &&
1094-
(<CallExpression>expression).arguments.length === 1;
1091+
const isRequire = expression.kind === SyntaxKind.CallExpression &&
1092+
(<CallExpression>expression).expression.kind === SyntaxKind.Identifier &&
1093+
(<Identifier>(<CallExpression>expression).expression).text === "require" &&
1094+
(<CallExpression>expression).arguments.length === 1;
1095+
1096+
return isRequire && (!checkArgumentIsStringLiteral || (<CallExpression>expression).arguments[0].kind === SyntaxKind.StringLiteral);
10951097
}
10961098

10971099
/// Given a BinaryExpression, returns SpecialPropertyAssignmentKind for the various kinds of property

tests/baselines/reference/baseCheck.errors.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
tests/cases/compiler/baseCheck.ts(9,18): error TS2304: Cannot find name 'loc'.
22
tests/cases/compiler/baseCheck.ts(17,53): error TS2346: Supplied parameters do not match any signature of call target.
3-
tests/cases/compiler/baseCheck.ts(17,59): error TS2332: 'this' cannot be referenced in current location.
4-
tests/cases/compiler/baseCheck.ts(18,62): error TS2332: 'this' cannot be referenced in current location.
3+
tests/cases/compiler/baseCheck.ts(17,59): error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
4+
tests/cases/compiler/baseCheck.ts(18,62): error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
55
tests/cases/compiler/baseCheck.ts(19,59): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
6-
tests/cases/compiler/baseCheck.ts(19,68): error TS2332: 'this' cannot be referenced in current location.
6+
tests/cases/compiler/baseCheck.ts(19,68): error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
77
tests/cases/compiler/baseCheck.ts(22,9): error TS2304: Cannot find name 'x'.
88
tests/cases/compiler/baseCheck.ts(23,7): error TS2304: Cannot find name 'x'.
99
tests/cases/compiler/baseCheck.ts(26,9): error TS2304: Cannot find name 'x'.
@@ -32,15 +32,15 @@ tests/cases/compiler/baseCheck.ts(26,9): error TS2304: Cannot find name 'x'.
3232
~~~~~~~~~~~~~
3333
!!! error TS2346: Supplied parameters do not match any signature of call target.
3434
~~~~
35-
!!! error TS2332: 'this' cannot be referenced in current location.
35+
!!! error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
3636
class E extends C { constructor(public z: number) { super(0, this.z) } }
3737
~~~~
38-
!!! error TS2332: 'this' cannot be referenced in current location.
38+
!!! error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
3939
class F extends C { constructor(public z: number) { super("hello", this.z) } } // first param type
4040
~~~~~~~
4141
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
4242
~~~~
43-
!!! error TS2332: 'this' cannot be referenced in current location.
43+
!!! error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
4444

4545
function f() {
4646
if (x<10) {

tests/baselines/reference/bases.errors.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@ tests/cases/compiler/bases.ts(7,17): error TS2304: Cannot find name 'any'.
44
tests/cases/compiler/bases.ts(11,7): error TS2420: Class 'C' incorrectly implements interface 'I'.
55
Property 'x' is missing in type 'C'.
66
tests/cases/compiler/bases.ts(12,5): error TS2377: Constructors for derived classes must contain a 'super' call.
7+
tests/cases/compiler/bases.ts(13,9): error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
78
tests/cases/compiler/bases.ts(13,14): error TS2339: Property 'x' does not exist on type 'C'.
89
tests/cases/compiler/bases.ts(13,15): error TS1005: ';' expected.
910
tests/cases/compiler/bases.ts(13,17): error TS2304: Cannot find name 'any'.
1011
tests/cases/compiler/bases.ts(17,9): error TS2339: Property 'x' does not exist on type 'C'.
1112
tests/cases/compiler/bases.ts(18,9): error TS2339: Property 'y' does not exist on type 'C'.
1213

1314

14-
==== tests/cases/compiler/bases.ts (10 errors) ====
15+
==== tests/cases/compiler/bases.ts (11 errors) ====
1516
interface I {
1617
x;
1718
}
@@ -36,6 +37,8 @@ tests/cases/compiler/bases.ts(18,9): error TS2339: Property 'y' does not exist o
3637
~~~~~~~~~~~~~~~
3738
this.x: any;
3839
~~~~~~~~~~~~~~~~~~~~
40+
~~~~
41+
!!! error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
3942
~
4043
!!! error TS2339: Property 'x' does not exist on type 'C'.
4144
~
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//// [checkSuperCallBeforeThisAccessing1.ts]
2+
class Based { }
3+
class Derived extends Based {
4+
public x: number;
5+
constructor() {
6+
super();
7+
this;
8+
this.x = 10;
9+
var that = this;
10+
}
11+
}
12+
13+
//// [checkSuperCallBeforeThisAccessing1.js]
14+
var __extends = (this && this.__extends) || function (d, b) {
15+
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
16+
function __() { this.constructor = d; }
17+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
18+
};
19+
var Based = (function () {
20+
function Based() {
21+
}
22+
return Based;
23+
}());
24+
var Derived = (function (_super) {
25+
__extends(Derived, _super);
26+
function Derived() {
27+
_super.call(this);
28+
this;
29+
this.x = 10;
30+
var that = this;
31+
}
32+
return Derived;
33+
}(Based));
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
=== tests/cases/compiler/checkSuperCallBeforeThisAccessing1.ts ===
2+
class Based { }
3+
>Based : Symbol(Based, Decl(checkSuperCallBeforeThisAccessing1.ts, 0, 0))
4+
5+
class Derived extends Based {
6+
>Derived : Symbol(Derived, Decl(checkSuperCallBeforeThisAccessing1.ts, 0, 15))
7+
>Based : Symbol(Based, Decl(checkSuperCallBeforeThisAccessing1.ts, 0, 0))
8+
9+
public x: number;
10+
>x : Symbol(x, Decl(checkSuperCallBeforeThisAccessing1.ts, 1, 29))
11+
12+
constructor() {
13+
super();
14+
>super : Symbol(Based, Decl(checkSuperCallBeforeThisAccessing1.ts, 0, 0))
15+
16+
this;
17+
>this : Symbol(Derived, Decl(checkSuperCallBeforeThisAccessing1.ts, 0, 15))
18+
19+
this.x = 10;
20+
>this.x : Symbol(x, Decl(checkSuperCallBeforeThisAccessing1.ts, 1, 29))
21+
>this : Symbol(Derived, Decl(checkSuperCallBeforeThisAccessing1.ts, 0, 15))
22+
>x : Symbol(x, Decl(checkSuperCallBeforeThisAccessing1.ts, 1, 29))
23+
24+
var that = this;
25+
>that : Symbol(that, Decl(checkSuperCallBeforeThisAccessing1.ts, 7, 11))
26+
>this : Symbol(Derived, Decl(checkSuperCallBeforeThisAccessing1.ts, 0, 15))
27+
}
28+
}

0 commit comments

Comments
 (0)