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
17 changes: 13 additions & 4 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7267,6 +7267,14 @@ namespace ts {
let container = getThisContainer(node, /* includeArrowFunctions */ true);
let needToCaptureLexicalThis = false;

if (container.kind === SyntaxKind.Constructor) {
const baseTypeNode = getClassExtendsHeritageClauseElement(<ClassLikeDeclaration>container.parent);
if (baseTypeNode && !(getNodeCheckFlags(container) & NodeCheckFlags.HasSeenSuperCall)) {
// In ES6, super inside constructor of class-declaration has to precede "this" accessing
error(node, Diagnostics.super_must_be_called_before_accessing_this_in_the_constructor_of_a_derived_class);
}
}

// Now skip arrow functions to get the "real" owner of 'this'.
if (container.kind === SyntaxKind.ArrowFunction) {
container = getThisContainer(container, /* includeArrowFunctions */ false);
Expand Down Expand Up @@ -10213,6 +10221,11 @@ namespace ts {

const signature = getResolvedSignature(node);
if (node.expression.kind === SyntaxKind.SuperKeyword) {
const containgFunction = getContainingFunction(node.expression);

if (containgFunction && containgFunction.kind === SyntaxKind.Constructor) {
getNodeLinks(containgFunction).flags |= NodeCheckFlags.HasSeenSuperCall;
}
return voidType;
}
if (node.kind === SyntaxKind.NewExpression) {
Expand Down Expand Up @@ -11829,10 +11842,6 @@ namespace ts {
if (!superCallStatement) {
error(node, Diagnostics.A_super_call_must_be_the_first_statement_in_the_constructor_when_a_class_contains_initialized_properties_or_has_parameter_properties);
}
else {
// In such a required super call, it is a compile-time error for argument expressions to reference this.
markThisReferencesAsErrors(superCallStatement.expression);
}
}
}
else if (baseConstructorType !== nullType) {
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -2771,5 +2771,9 @@
"JSX element '{0}' has no corresponding closing tag.": {
"category": "Error",
"code": 17008
},
"'super' must be called before accessing 'this' in the constructor of a derived class.": {
"category": "Error",
"code": 17009
}
}
1 change: 1 addition & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2070,6 +2070,7 @@ namespace ts {
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'
}

/* @internal */
Expand Down
12 changes: 6 additions & 6 deletions tests/baselines/reference/baseCheck.errors.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
tests/cases/compiler/baseCheck.ts(9,18): error TS2304: Cannot find name 'loc'.
tests/cases/compiler/baseCheck.ts(17,53): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/compiler/baseCheck.ts(17,59): error TS2332: 'this' cannot be referenced in current location.
tests/cases/compiler/baseCheck.ts(18,62): error TS2332: 'this' cannot be referenced in current location.
tests/cases/compiler/baseCheck.ts(17,59): error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
tests/cases/compiler/baseCheck.ts(18,62): error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
tests/cases/compiler/baseCheck.ts(19,59): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
tests/cases/compiler/baseCheck.ts(19,68): error TS2332: 'this' cannot be referenced in current location.
tests/cases/compiler/baseCheck.ts(19,68): error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
tests/cases/compiler/baseCheck.ts(22,9): error TS2304: Cannot find name 'x'.
tests/cases/compiler/baseCheck.ts(23,7): error TS2304: Cannot find name 'x'.
tests/cases/compiler/baseCheck.ts(26,9): error TS2304: Cannot find name 'x'.
Expand Down Expand Up @@ -32,15 +32,15 @@ tests/cases/compiler/baseCheck.ts(26,9): error TS2304: Cannot find name 'x'.
~~~~~~~~~~~~~
!!! error TS2346: Supplied parameters do not match any signature of call target.
~~~~
!!! error TS2332: 'this' cannot be referenced in current location.
!!! error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
class E extends C { constructor(public z: number) { super(0, this.z) } }
~~~~
!!! error TS2332: 'this' cannot be referenced in current location.
!!! error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
class F extends C { constructor(public z: number) { super("hello", this.z) } } // first param type
~~~~~~~
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
~~~~
!!! error TS2332: 'this' cannot be referenced in current location.
!!! error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.

function f() {
if (x<10) {
Expand Down
5 changes: 4 additions & 1 deletion tests/baselines/reference/bases.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ tests/cases/compiler/bases.ts(7,17): error TS2304: Cannot find name 'any'.
tests/cases/compiler/bases.ts(11,7): error TS2420: Class 'C' incorrectly implements interface 'I'.
Property 'x' is missing in type 'C'.
tests/cases/compiler/bases.ts(12,5): error TS2377: Constructors for derived classes must contain a 'super' call.
tests/cases/compiler/bases.ts(13,9): error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
tests/cases/compiler/bases.ts(13,14): error TS2339: Property 'x' does not exist on type 'C'.
tests/cases/compiler/bases.ts(13,15): error TS1005: ';' expected.
tests/cases/compiler/bases.ts(13,17): error TS2304: Cannot find name 'any'.
tests/cases/compiler/bases.ts(17,9): error TS2339: Property 'x' does not exist on type 'C'.
tests/cases/compiler/bases.ts(18,9): error TS2339: Property 'y' does not exist on type 'C'.


==== tests/cases/compiler/bases.ts (10 errors) ====
==== tests/cases/compiler/bases.ts (11 errors) ====
interface I {
x;
}
Expand All @@ -36,6 +37,8 @@ tests/cases/compiler/bases.ts(18,9): error TS2339: Property 'y' does not exist o
~~~~~~~~~~~~~~~
this.x: any;
~~~~~~~~~~~~~~~~~~~~
~~~~
!!! error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
~
!!! error TS2339: Property 'x' does not exist on type 'C'.
~
Expand Down
33 changes: 33 additions & 0 deletions tests/baselines/reference/checkSuperCallBeforeThisAccessing1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//// [checkSuperCallBeforeThisAccessing1.ts]
class Based { }
class Derived extends Based {
public x: number;
constructor() {
super();
this;
this.x = 10;
var that = this;
}
}

//// [checkSuperCallBeforeThisAccessing1.js]
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var Based = (function () {
function Based() {
}
return Based;
}());
var Derived = (function (_super) {
__extends(Derived, _super);
function Derived() {
_super.call(this);
this;
this.x = 10;
var that = this;
}
return Derived;
}(Based));
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
=== tests/cases/compiler/checkSuperCallBeforeThisAccessing1.ts ===
class Based { }
>Based : Symbol(Based, Decl(checkSuperCallBeforeThisAccessing1.ts, 0, 0))

class Derived extends Based {
>Derived : Symbol(Derived, Decl(checkSuperCallBeforeThisAccessing1.ts, 0, 15))
>Based : Symbol(Based, Decl(checkSuperCallBeforeThisAccessing1.ts, 0, 0))

public x: number;
>x : Symbol(x, Decl(checkSuperCallBeforeThisAccessing1.ts, 1, 29))

constructor() {
super();
>super : Symbol(Based, Decl(checkSuperCallBeforeThisAccessing1.ts, 0, 0))

this;
>this : Symbol(Derived, Decl(checkSuperCallBeforeThisAccessing1.ts, 0, 15))

this.x = 10;
>this.x : Symbol(x, Decl(checkSuperCallBeforeThisAccessing1.ts, 1, 29))
>this : Symbol(Derived, Decl(checkSuperCallBeforeThisAccessing1.ts, 0, 15))
>x : Symbol(x, Decl(checkSuperCallBeforeThisAccessing1.ts, 1, 29))

var that = this;
>that : Symbol(that, Decl(checkSuperCallBeforeThisAccessing1.ts, 7, 11))
>this : Symbol(Derived, Decl(checkSuperCallBeforeThisAccessing1.ts, 0, 15))
}
}
31 changes: 31 additions & 0 deletions tests/baselines/reference/checkSuperCallBeforeThisAccessing1.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
=== tests/cases/compiler/checkSuperCallBeforeThisAccessing1.ts ===
class Based { }
>Based : Based

class Derived extends Based {
>Derived : Derived
>Based : Based

public x: number;
>x : number

constructor() {
super();
>super() : void
>super : typeof Based

this;
>this : this

this.x = 10;
>this.x = 10 : number
>this.x : number
>this : this
>x : number
>10 : number

var that = this;
>that : this
>this : this
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
tests/cases/compiler/checkSuperCallBeforeThisAccessing2.ts(5,9): error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.


==== tests/cases/compiler/checkSuperCallBeforeThisAccessing2.ts (1 errors) ====
class Based { }
class Derived extends Based {
public x: number;
constructor() {
this.x = 100;
~~~~
!!! error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
super();
this.x = 10;
var that = this;
}
}
33 changes: 33 additions & 0 deletions tests/baselines/reference/checkSuperCallBeforeThisAccessing2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//// [checkSuperCallBeforeThisAccessing2.ts]
class Based { }
class Derived extends Based {
public x: number;
constructor() {
this.x = 100;
super();
this.x = 10;
var that = this;
}
}

//// [checkSuperCallBeforeThisAccessing2.js]
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var Based = (function () {
function Based() {
}
return Based;
}());
var Derived = (function (_super) {
__extends(Derived, _super);
function Derived() {
this.x = 100;
_super.call(this);
this.x = 10;
var that = this;
}
return Derived;
}(Based));
43 changes: 43 additions & 0 deletions tests/baselines/reference/checkSuperCallBeforeThisAccessing3.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//// [checkSuperCallBeforeThisAccessing3.ts]
class Based { }
class Derived extends Based {
public x: number;
constructor() {
class innver {
public y: boolean;
constructor() {
this.y = true;
}
}
super();
this.x = 10;
var that = this;
}
}

//// [checkSuperCallBeforeThisAccessing3.js]
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var Based = (function () {
function Based() {
}
return Based;
}());
var Derived = (function (_super) {
__extends(Derived, _super);
function Derived() {
var innver = (function () {
function innver() {
this.y = true;
}
return innver;
}());
_super.call(this);
this.x = 10;
var that = this;
}
return Derived;
}(Based));
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
=== tests/cases/compiler/checkSuperCallBeforeThisAccessing3.ts ===
class Based { }
>Based : Symbol(Based, Decl(checkSuperCallBeforeThisAccessing3.ts, 0, 0))

class Derived extends Based {
>Derived : Symbol(Derived, Decl(checkSuperCallBeforeThisAccessing3.ts, 0, 15))
>Based : Symbol(Based, Decl(checkSuperCallBeforeThisAccessing3.ts, 0, 0))

public x: number;
>x : Symbol(x, Decl(checkSuperCallBeforeThisAccessing3.ts, 1, 29))

constructor() {
class innver {
>innver : Symbol(innver, Decl(checkSuperCallBeforeThisAccessing3.ts, 3, 19))

public y: boolean;
>y : Symbol(y, Decl(checkSuperCallBeforeThisAccessing3.ts, 4, 22))

constructor() {
this.y = true;
>this.y : Symbol(y, Decl(checkSuperCallBeforeThisAccessing3.ts, 4, 22))
>this : Symbol(innver, Decl(checkSuperCallBeforeThisAccessing3.ts, 3, 19))
>y : Symbol(y, Decl(checkSuperCallBeforeThisAccessing3.ts, 4, 22))
}
}
super();
>super : Symbol(Based, Decl(checkSuperCallBeforeThisAccessing3.ts, 0, 0))

this.x = 10;
>this.x : Symbol(x, Decl(checkSuperCallBeforeThisAccessing3.ts, 1, 29))
>this : Symbol(Derived, Decl(checkSuperCallBeforeThisAccessing3.ts, 0, 15))
>x : Symbol(x, Decl(checkSuperCallBeforeThisAccessing3.ts, 1, 29))

var that = this;
>that : Symbol(that, Decl(checkSuperCallBeforeThisAccessing3.ts, 12, 11))
>this : Symbol(Derived, Decl(checkSuperCallBeforeThisAccessing3.ts, 0, 15))
}
}
43 changes: 43 additions & 0 deletions tests/baselines/reference/checkSuperCallBeforeThisAccessing3.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
=== tests/cases/compiler/checkSuperCallBeforeThisAccessing3.ts ===
class Based { }
>Based : Based

class Derived extends Based {
>Derived : Derived
>Based : Based

public x: number;
>x : number

constructor() {
class innver {
>innver : innver

public y: boolean;
>y : boolean

constructor() {
this.y = true;
>this.y = true : boolean
>this.y : boolean
>this : this
>y : boolean
>true : boolean
}
}
super();
>super() : void
>super : typeof Based

this.x = 10;
>this.x = 10 : number
>this.x : number
>this : this
>x : number
>10 : number

var that = this;
>that : this
>this : this
}
}
Loading