Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add error for super property before super #12690

Merged
merged 3 commits into from
Dec 6, 2016
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
48 changes: 28 additions & 20 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10405,33 +10405,37 @@ namespace ts {
return baseConstructorType === nullWideningType;
}

function checkThisBeforeSuper(node: Node, container: Node, diagnosticMessage: DiagnosticMessage) {
const containingClassDecl = <ClassDeclaration>container.parent;
const baseTypeNode = getClassExtendsHeritageClauseElement(containingClassDecl);

// If a containing class does not have extends clause or the class extends null
// skip checking whether super statement is called before "this" accessing.
if (baseTypeNode && !classDeclarationExtendsNull(containingClassDecl)) {
const superCall = getSuperCallInConstructor(<ConstructorDeclaration>container);

// We should give an error in the following cases:
// - No super-call
// - "this" is accessing before super-call.
// i.e super(this)
// this.x; super();
// We want to make sure that super-call is done before accessing "this" so that
// "this" is not accessed as a parameter of the super-call.
if (!superCall || superCall.end > node.pos) {
// In ES6, super inside constructor of class-declaration has to precede "this" accessing
error(node, diagnosticMessage);
}
}
}

function checkThisExpression(node: Node): Type {
// Stop at the first arrow function so that we can
// tell whether 'this' needs to be captured.
let container = getThisContainer(node, /* includeArrowFunctions */ true);
let needToCaptureLexicalThis = false;

if (container.kind === SyntaxKind.Constructor) {
const containingClassDecl = <ClassDeclaration>container.parent;
const baseTypeNode = getClassExtendsHeritageClauseElement(containingClassDecl);

// If a containing class does not have extends clause or the class extends null
// skip checking whether super statement is called before "this" accessing.
if (baseTypeNode && !classDeclarationExtendsNull(containingClassDecl)) {
const superCall = getSuperCallInConstructor(<ConstructorDeclaration>container);

// We should give an error in the following cases:
// - No super-call
// - "this" is accessing before super-call.
// i.e super(this)
// this.x; super();
// We want to make sure that super-call is done before accessing "this" so that
// "this" is not accessed as a parameter of the super-call.
if (!superCall || superCall.end > node.pos) {
// 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);
}
}
checkThisBeforeSuper(node, container, 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'.
Expand Down Expand Up @@ -10579,6 +10583,10 @@ namespace ts {
return unknownType;
}

if (!isCallExpression && container.kind === SyntaxKind.Constructor) {
checkThisBeforeSuper(node, container, Diagnostics.super_must_be_called_before_accessing_a_property_of_super_in_the_constructor_of_a_derived_class);
}

if ((getModifierFlags(container) & ModifierFlags.Static) || isCallExpression) {
nodeCheckFlag = NodeCheckFlags.SuperStatic;
}
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -3165,6 +3165,10 @@
"category": "Error",
"code": 17010
},
"'super' must be called before accessing a property of 'super' in the constructor of a derived class.": {
"category": "Error",
"code": 17011
},

"Circularity detected while resolving configuration: {0}": {
"category": "Error",
Expand Down
1 change: 0 additions & 1 deletion src/compiler/transformers/es2015.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2837,7 +2837,6 @@ namespace ts {
// _super.call(this, a)
// _super.m.call(this, a)
// _super.prototype.m.call(this, a)

resultingCall = createFunctionCall(
visitNode(target, visitor, isExpression),
visitNode(thisArg, visitor, isExpression),
Expand Down
5 changes: 4 additions & 1 deletion tests/baselines/reference/errorSuperCalls.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ tests/cases/conformance/expressions/superCalls/errorSuperCalls.ts(26,9): error T
tests/cases/conformance/expressions/superCalls/errorSuperCalls.ts(30,16): error TS2337: Super calls are not permitted outside constructors or in nested functions inside constructors.
tests/cases/conformance/expressions/superCalls/errorSuperCalls.ts(34,9): error TS2337: Super calls are not permitted outside constructors or in nested functions inside constructors.
tests/cases/conformance/expressions/superCalls/errorSuperCalls.ts(38,9): error TS2337: Super calls are not permitted outside constructors or in nested functions inside constructors.
tests/cases/conformance/expressions/superCalls/errorSuperCalls.ts(46,9): error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
tests/cases/conformance/expressions/superCalls/errorSuperCalls.ts(46,14): error TS1034: 'super' must be followed by an argument list or member access.
tests/cases/conformance/expressions/superCalls/errorSuperCalls.ts(58,9): error TS2337: Super calls are not permitted outside constructors or in nested functions inside constructors.
tests/cases/conformance/expressions/superCalls/errorSuperCalls.ts(62,9): error TS2337: Super calls are not permitted outside constructors or in nested functions inside constructors.
tests/cases/conformance/expressions/superCalls/errorSuperCalls.ts(67,9): error TS2337: Super calls are not permitted outside constructors or in nested functions inside constructors.
tests/cases/conformance/expressions/superCalls/errorSuperCalls.ts(71,9): error TS2337: Super calls are not permitted outside constructors or in nested functions inside constructors.


==== tests/cases/conformance/expressions/superCalls/errorSuperCalls.ts (14 errors) ====
==== tests/cases/conformance/expressions/superCalls/errorSuperCalls.ts (15 errors) ====
//super call in class constructor with no base type
class NoBase {
constructor() {
Expand Down Expand Up @@ -79,6 +80,8 @@ tests/cases/conformance/expressions/superCalls/errorSuperCalls.ts(71,9): error T
//super call with type arguments
constructor() {
super<string>();
~~~~~
!!! error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
~
!!! error TS1034: 'super' must be followed by an argument list or member access.
super();
Expand Down
11 changes: 10 additions & 1 deletion tests/baselines/reference/superAccess2.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@ tests/cases/compiler/superAccess2.ts(7,15): error TS1034: 'super' must be follow
tests/cases/compiler/superAccess2.ts(8,17): error TS2338: 'super' property access is permitted only in a constructor, member function, or member accessor of a derived class.
tests/cases/compiler/superAccess2.ts(8,22): error TS1034: 'super' must be followed by an argument list or member access.
tests/cases/compiler/superAccess2.ts(11,28): error TS2336: 'super' cannot be referenced in constructor arguments.
tests/cases/compiler/superAccess2.ts(11,28): error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
tests/cases/compiler/superAccess2.ts(11,33): error TS1034: 'super' must be followed by an argument list or member access.
tests/cases/compiler/superAccess2.ts(11,40): error TS2336: 'super' cannot be referenced in constructor arguments.
tests/cases/compiler/superAccess2.ts(11,40): error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
tests/cases/compiler/superAccess2.ts(11,45): error TS1034: 'super' must be followed by an argument list or member access.
tests/cases/compiler/superAccess2.ts(11,59): error TS2336: 'super' cannot be referenced in constructor arguments.
tests/cases/compiler/superAccess2.ts(11,59): error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
tests/cases/compiler/superAccess2.ts(11,64): error TS1034: 'super' must be followed by an argument list or member access.
tests/cases/compiler/superAccess2.ts(15,19): error TS1034: 'super' must be followed by an argument list or member access.
tests/cases/compiler/superAccess2.ts(17,15): error TS2339: Property 'y' does not exist on type 'P'.
tests/cases/compiler/superAccess2.ts(20,26): error TS1034: 'super' must be followed by an argument list or member access.
tests/cases/compiler/superAccess2.ts(21,15): error TS2339: Property 'x' does not exist on type 'typeof P'.


==== tests/cases/compiler/superAccess2.ts (13 errors) ====
==== tests/cases/compiler/superAccess2.ts (16 errors) ====
class P {
x() { }
static y() { }
Expand All @@ -33,14 +36,20 @@ tests/cases/compiler/superAccess2.ts(21,15): error TS2339: Property 'x' does not
constructor(public z = super, zz = super, zzz = () => super) {
~~~~~
!!! error TS2336: 'super' cannot be referenced in constructor arguments.
~~~~~
!!! error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
~
!!! error TS1034: 'super' must be followed by an argument list or member access.
~~~~~
!!! error TS2336: 'super' cannot be referenced in constructor arguments.
~~~~~
!!! error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
~
!!! error TS1034: 'super' must be followed by an argument list or member access.
~~~~~
!!! error TS2336: 'super' cannot be referenced in constructor arguments.
~~~~~
!!! error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
~
!!! error TS1034: 'super' must be followed by an argument list or member access.
super();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
tests/cases/compiler/superInConstructorParam1.ts(8,3): error TS2377: Constructors for derived classes must contain a 'super' call.
tests/cases/compiler/superInConstructorParam1.ts(8,19): error TS2336: 'super' cannot be referenced in constructor arguments.
tests/cases/compiler/superInConstructorParam1.ts(8,19): error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.


==== tests/cases/compiler/superInConstructorParam1.ts (2 errors) ====
==== tests/cases/compiler/superInConstructorParam1.ts (3 errors) ====
class B {
public foo(): number {
return 0;
Expand All @@ -14,6 +15,8 @@ tests/cases/compiler/superInConstructorParam1.ts(8,19): error TS2336: 'super' ca
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~
!!! error TS2336: 'super' cannot be referenced in constructor arguments.
~~~~~
!!! error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
}
~~~
!!! error TS2377: Constructors for derived classes must contain a 'super' call.
Expand Down
5 changes: 4 additions & 1 deletion tests/baselines/reference/superNewCall1.errors.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
tests/cases/compiler/superNewCall1.ts(9,5): error TS2377: Constructors for derived classes must contain a 'super' call.
tests/cases/compiler/superNewCall1.ts(10,9): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
tests/cases/compiler/superNewCall1.ts(10,13): error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.


==== tests/cases/compiler/superNewCall1.ts (2 errors) ====
==== tests/cases/compiler/superNewCall1.ts (3 errors) ====

class A<T1, T2> {
constructor(private map: (value: T1) => T2) {
Expand All @@ -17,6 +18,8 @@ tests/cases/compiler/superNewCall1.ts(10,9): error TS2351: Cannot use 'new' with
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
~~~~~
!!! error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
}
~~~~~
!!! error TS2377: Constructors for derived classes must contain a 'super' call.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
tests/cases/conformance/classes/constructorDeclarations/superCalls/superPropertyInConstructorBeforeSuperCall.ts(7,9): error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
tests/cases/conformance/classes/constructorDeclarations/superCalls/superPropertyInConstructorBeforeSuperCall.ts(13,15): error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.


==== tests/cases/conformance/classes/constructorDeclarations/superCalls/superPropertyInConstructorBeforeSuperCall.ts (2 errors) ====
class B {
constructor(x?: string) {}
x(): string { return ""; }
}
class C1 extends B {
constructor() {
super.x();
~~~~~
!!! error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
super();
}
}
class C2 extends B {
constructor() {
super(super.x());
~~~~~
!!! error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//// [superPropertyInConstructorBeforeSuperCall.ts]
class B {
constructor(x?: string) {}
x(): string { return ""; }
}
class C1 extends B {
constructor() {
super.x();
super();
}
}
class C2 extends B {
constructor() {
super(super.x());
}
}

//// [superPropertyInConstructorBeforeSuperCall.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 B = (function () {
function B(x) {
}
B.prototype.x = function () { return ""; };
return B;
}());
var C1 = (function (_super) {
__extends(C1, _super);
function C1() {
var _this;
_super.prototype.x.call(_this);
_this = _super.call(this) || this;
return _this;
}
return C1;
}(B));
var C2 = (function (_super) {
__extends(C2, _super);
function C2() {
return _super.call(this, _super.x.call(_this)) || this;
}
return C2;
}(B));
5 changes: 4 additions & 1 deletion tests/baselines/reference/superWithTypeArgument.errors.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
tests/cases/compiler/superWithTypeArgument.ts(6,5): error TS2377: Constructors for derived classes must contain a 'super' call.
tests/cases/compiler/superWithTypeArgument.ts(7,9): error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
tests/cases/compiler/superWithTypeArgument.ts(7,14): error TS1034: 'super' must be followed by an argument list or member access.


==== tests/cases/compiler/superWithTypeArgument.ts (2 errors) ====
==== tests/cases/compiler/superWithTypeArgument.ts (3 errors) ====
class C {

}
Expand All @@ -12,6 +13,8 @@ tests/cases/compiler/superWithTypeArgument.ts(7,14): error TS1034: 'super' must
~~~~~~~~~~~~~~~
super<T>();
~~~~~~~~~~~~~~~~~~~
~~~~~
!!! error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
~
!!! error TS1034: 'super' must be followed by an argument list or member access.
}
Expand Down
5 changes: 4 additions & 1 deletion tests/baselines/reference/superWithTypeArgument2.errors.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
tests/cases/compiler/superWithTypeArgument2.ts(6,5): error TS2377: Constructors for derived classes must contain a 'super' call.
tests/cases/compiler/superWithTypeArgument2.ts(7,9): error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
tests/cases/compiler/superWithTypeArgument2.ts(7,14): error TS1034: 'super' must be followed by an argument list or member access.


==== tests/cases/compiler/superWithTypeArgument2.ts (2 errors) ====
==== tests/cases/compiler/superWithTypeArgument2.ts (3 errors) ====
class C<T> {
foo: T;
}
Expand All @@ -12,6 +13,8 @@ tests/cases/compiler/superWithTypeArgument2.ts(7,14): error TS1034: 'super' must
~~~~~~~~~~~~~~~~
super<T>(x);
~~~~~~~~~~~~~~~~~~~~
~~~~~
!!! error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
~
!!! error TS1034: 'super' must be followed by an argument list or member access.
}
Expand Down
5 changes: 4 additions & 1 deletion tests/baselines/reference/superWithTypeArgument3.errors.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
tests/cases/compiler/superWithTypeArgument3.ts(7,5): error TS2377: Constructors for derived classes must contain a 'super' call.
tests/cases/compiler/superWithTypeArgument3.ts(8,9): error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
tests/cases/compiler/superWithTypeArgument3.ts(8,14): error TS1034: 'super' must be followed by an argument list or member access.


==== tests/cases/compiler/superWithTypeArgument3.ts (2 errors) ====
==== tests/cases/compiler/superWithTypeArgument3.ts (3 errors) ====
class C<T> {
foo: T;
bar<U>(x: U) { }
Expand All @@ -13,6 +14,8 @@ tests/cases/compiler/superWithTypeArgument3.ts(8,14): error TS1034: 'super' must
~~~~~~~~~~~~~~~
super<T>();
~~~~~~~~~~~~~~~~~~~
~~~~~
!!! error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
~
!!! error TS1034: 'super' must be followed by an argument list or member access.
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class B {
constructor(x?: string) {}
x(): string { return ""; }
}
class C1 extends B {
constructor() {
super.x();
super();
}
}
class C2 extends B {
constructor() {
super(super.x());
}
}