Skip to content

Commit 847b42d

Browse files
authored
Merge pull request #12690 from Microsoft/fix12669
Add error for super property before super
2 parents 8f2d531 + e8024e4 commit 847b42d

13 files changed

+151
-28
lines changed

src/compiler/checker.ts

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10405,33 +10405,37 @@ namespace ts {
1040510405
return baseConstructorType === nullWideningType;
1040610406
}
1040710407

10408+
function checkThisBeforeSuper(node: Node, container: Node, diagnosticMessage: DiagnosticMessage) {
10409+
const containingClassDecl = <ClassDeclaration>container.parent;
10410+
const baseTypeNode = getClassExtendsHeritageClauseElement(containingClassDecl);
10411+
10412+
// If a containing class does not have extends clause or the class extends null
10413+
// skip checking whether super statement is called before "this" accessing.
10414+
if (baseTypeNode && !classDeclarationExtendsNull(containingClassDecl)) {
10415+
const superCall = getSuperCallInConstructor(<ConstructorDeclaration>container);
10416+
10417+
// We should give an error in the following cases:
10418+
// - No super-call
10419+
// - "this" is accessing before super-call.
10420+
// i.e super(this)
10421+
// this.x; super();
10422+
// We want to make sure that super-call is done before accessing "this" so that
10423+
// "this" is not accessed as a parameter of the super-call.
10424+
if (!superCall || superCall.end > node.pos) {
10425+
// In ES6, super inside constructor of class-declaration has to precede "this" accessing
10426+
error(node, diagnosticMessage);
10427+
}
10428+
}
10429+
}
10430+
1040810431
function checkThisExpression(node: Node): Type {
1040910432
// Stop at the first arrow function so that we can
1041010433
// tell whether 'this' needs to be captured.
1041110434
let container = getThisContainer(node, /* includeArrowFunctions */ true);
1041210435
let needToCaptureLexicalThis = false;
1041310436

1041410437
if (container.kind === SyntaxKind.Constructor) {
10415-
const containingClassDecl = <ClassDeclaration>container.parent;
10416-
const baseTypeNode = getClassExtendsHeritageClauseElement(containingClassDecl);
10417-
10418-
// If a containing class does not have extends clause or the class extends null
10419-
// skip checking whether super statement is called before "this" accessing.
10420-
if (baseTypeNode && !classDeclarationExtendsNull(containingClassDecl)) {
10421-
const superCall = getSuperCallInConstructor(<ConstructorDeclaration>container);
10422-
10423-
// We should give an error in the following cases:
10424-
// - No super-call
10425-
// - "this" is accessing before super-call.
10426-
// i.e super(this)
10427-
// this.x; super();
10428-
// We want to make sure that super-call is done before accessing "this" so that
10429-
// "this" is not accessed as a parameter of the super-call.
10430-
if (!superCall || superCall.end > node.pos) {
10431-
// In ES6, super inside constructor of class-declaration has to precede "this" accessing
10432-
error(node, Diagnostics.super_must_be_called_before_accessing_this_in_the_constructor_of_a_derived_class);
10433-
}
10434-
}
10438+
checkThisBeforeSuper(node, container, Diagnostics.super_must_be_called_before_accessing_this_in_the_constructor_of_a_derived_class);
1043510439
}
1043610440

1043710441
// Now skip arrow functions to get the "real" owner of 'this'.
@@ -10579,6 +10583,10 @@ namespace ts {
1057910583
return unknownType;
1058010584
}
1058110585

10586+
if (!isCallExpression && container.kind === SyntaxKind.Constructor) {
10587+
checkThisBeforeSuper(node, container, Diagnostics.super_must_be_called_before_accessing_a_property_of_super_in_the_constructor_of_a_derived_class);
10588+
}
10589+
1058210590
if ((getModifierFlags(container) & ModifierFlags.Static) || isCallExpression) {
1058310591
nodeCheckFlag = NodeCheckFlags.SuperStatic;
1058410592
}

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3165,6 +3165,10 @@
31653165
"category": "Error",
31663166
"code": 17010
31673167
},
3168+
"'super' must be called before accessing a property of 'super' in the constructor of a derived class.": {
3169+
"category": "Error",
3170+
"code": 17011
3171+
},
31683172

31693173
"Circularity detected while resolving configuration: {0}": {
31703174
"category": "Error",

src/compiler/transformers/es2015.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2837,7 +2837,6 @@ namespace ts {
28372837
// _super.call(this, a)
28382838
// _super.m.call(this, a)
28392839
// _super.prototype.m.call(this, a)
2840-
28412840
resultingCall = createFunctionCall(
28422841
visitNode(target, visitor, isExpression),
28432842
visitNode(thisArg, visitor, isExpression),

tests/baselines/reference/errorSuperCalls.errors.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@ tests/cases/conformance/expressions/superCalls/errorSuperCalls.ts(26,9): error T
77
tests/cases/conformance/expressions/superCalls/errorSuperCalls.ts(30,16): error TS2337: Super calls are not permitted outside constructors or in nested functions inside constructors.
88
tests/cases/conformance/expressions/superCalls/errorSuperCalls.ts(34,9): error TS2337: Super calls are not permitted outside constructors or in nested functions inside constructors.
99
tests/cases/conformance/expressions/superCalls/errorSuperCalls.ts(38,9): error TS2337: Super calls are not permitted outside constructors or in nested functions inside constructors.
10+
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.
1011
tests/cases/conformance/expressions/superCalls/errorSuperCalls.ts(46,14): error TS1034: 'super' must be followed by an argument list or member access.
1112
tests/cases/conformance/expressions/superCalls/errorSuperCalls.ts(58,9): error TS2337: Super calls are not permitted outside constructors or in nested functions inside constructors.
1213
tests/cases/conformance/expressions/superCalls/errorSuperCalls.ts(62,9): error TS2337: Super calls are not permitted outside constructors or in nested functions inside constructors.
1314
tests/cases/conformance/expressions/superCalls/errorSuperCalls.ts(67,9): error TS2337: Super calls are not permitted outside constructors or in nested functions inside constructors.
1415
tests/cases/conformance/expressions/superCalls/errorSuperCalls.ts(71,9): error TS2337: Super calls are not permitted outside constructors or in nested functions inside constructors.
1516

1617

17-
==== tests/cases/conformance/expressions/superCalls/errorSuperCalls.ts (14 errors) ====
18+
==== tests/cases/conformance/expressions/superCalls/errorSuperCalls.ts (15 errors) ====
1819
//super call in class constructor with no base type
1920
class NoBase {
2021
constructor() {
@@ -79,6 +80,8 @@ tests/cases/conformance/expressions/superCalls/errorSuperCalls.ts(71,9): error T
7980
//super call with type arguments
8081
constructor() {
8182
super<string>();
83+
~~~~~
84+
!!! error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
8285
~
8386
!!! error TS1034: 'super' must be followed by an argument list or member access.
8487
super();

tests/baselines/reference/superAccess2.errors.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,21 @@ tests/cases/compiler/superAccess2.ts(7,15): error TS1034: 'super' must be follow
22
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.
33
tests/cases/compiler/superAccess2.ts(8,22): error TS1034: 'super' must be followed by an argument list or member access.
44
tests/cases/compiler/superAccess2.ts(11,28): error TS2336: 'super' cannot be referenced in constructor arguments.
5+
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.
56
tests/cases/compiler/superAccess2.ts(11,33): error TS1034: 'super' must be followed by an argument list or member access.
67
tests/cases/compiler/superAccess2.ts(11,40): error TS2336: 'super' cannot be referenced in constructor arguments.
8+
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.
79
tests/cases/compiler/superAccess2.ts(11,45): error TS1034: 'super' must be followed by an argument list or member access.
810
tests/cases/compiler/superAccess2.ts(11,59): error TS2336: 'super' cannot be referenced in constructor arguments.
11+
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.
912
tests/cases/compiler/superAccess2.ts(11,64): error TS1034: 'super' must be followed by an argument list or member access.
1013
tests/cases/compiler/superAccess2.ts(15,19): error TS1034: 'super' must be followed by an argument list or member access.
1114
tests/cases/compiler/superAccess2.ts(17,15): error TS2339: Property 'y' does not exist on type 'P'.
1215
tests/cases/compiler/superAccess2.ts(20,26): error TS1034: 'super' must be followed by an argument list or member access.
1316
tests/cases/compiler/superAccess2.ts(21,15): error TS2339: Property 'x' does not exist on type 'typeof P'.
1417

1518

16-
==== tests/cases/compiler/superAccess2.ts (13 errors) ====
19+
==== tests/cases/compiler/superAccess2.ts (16 errors) ====
1720
class P {
1821
x() { }
1922
static y() { }
@@ -33,14 +36,20 @@ tests/cases/compiler/superAccess2.ts(21,15): error TS2339: Property 'x' does not
3336
constructor(public z = super, zz = super, zzz = () => super) {
3437
~~~~~
3538
!!! error TS2336: 'super' cannot be referenced in constructor arguments.
39+
~~~~~
40+
!!! error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
3641
~
3742
!!! error TS1034: 'super' must be followed by an argument list or member access.
3843
~~~~~
3944
!!! error TS2336: 'super' cannot be referenced in constructor arguments.
45+
~~~~~
46+
!!! error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
4047
~
4148
!!! error TS1034: 'super' must be followed by an argument list or member access.
4249
~~~~~
4350
!!! error TS2336: 'super' cannot be referenced in constructor arguments.
51+
~~~~~
52+
!!! error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
4453
~
4554
!!! error TS1034: 'super' must be followed by an argument list or member access.
4655
super();

tests/baselines/reference/superInConstructorParam1.errors.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
tests/cases/compiler/superInConstructorParam1.ts(8,3): error TS2377: Constructors for derived classes must contain a 'super' call.
22
tests/cases/compiler/superInConstructorParam1.ts(8,19): error TS2336: 'super' cannot be referenced in constructor arguments.
3+
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.
34

45

5-
==== tests/cases/compiler/superInConstructorParam1.ts (2 errors) ====
6+
==== tests/cases/compiler/superInConstructorParam1.ts (3 errors) ====
67
class B {
78
public foo(): number {
89
return 0;
@@ -14,6 +15,8 @@ tests/cases/compiler/superInConstructorParam1.ts(8,19): error TS2336: 'super' ca
1415
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1516
~~~~~
1617
!!! error TS2336: 'super' cannot be referenced in constructor arguments.
18+
~~~~~
19+
!!! error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
1720
}
1821
~~~
1922
!!! error TS2377: Constructors for derived classes must contain a 'super' call.

tests/baselines/reference/superNewCall1.errors.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
tests/cases/compiler/superNewCall1.ts(9,5): error TS2377: Constructors for derived classes must contain a 'super' call.
22
tests/cases/compiler/superNewCall1.ts(10,9): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
3+
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.
34

45

5-
==== tests/cases/compiler/superNewCall1.ts (2 errors) ====
6+
==== tests/cases/compiler/superNewCall1.ts (3 errors) ====
67

78
class A<T1, T2> {
89
constructor(private map: (value: T1) => T2) {
@@ -17,6 +18,8 @@ tests/cases/compiler/superNewCall1.ts(10,9): error TS2351: Cannot use 'new' with
1718
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1819
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1920
!!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
21+
~~~~~
22+
!!! error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
2023
}
2124
~~~~~
2225
!!! error TS2377: Constructors for derived classes must contain a 'super' call.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
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.
2+
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.
3+
4+
5+
==== tests/cases/conformance/classes/constructorDeclarations/superCalls/superPropertyInConstructorBeforeSuperCall.ts (2 errors) ====
6+
class B {
7+
constructor(x?: string) {}
8+
x(): string { return ""; }
9+
}
10+
class C1 extends B {
11+
constructor() {
12+
super.x();
13+
~~~~~
14+
!!! error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
15+
super();
16+
}
17+
}
18+
class C2 extends B {
19+
constructor() {
20+
super(super.x());
21+
~~~~~
22+
!!! error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
23+
}
24+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//// [superPropertyInConstructorBeforeSuperCall.ts]
2+
class B {
3+
constructor(x?: string) {}
4+
x(): string { return ""; }
5+
}
6+
class C1 extends B {
7+
constructor() {
8+
super.x();
9+
super();
10+
}
11+
}
12+
class C2 extends B {
13+
constructor() {
14+
super(super.x());
15+
}
16+
}
17+
18+
//// [superPropertyInConstructorBeforeSuperCall.js]
19+
var __extends = (this && this.__extends) || function (d, b) {
20+
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
21+
function __() { this.constructor = d; }
22+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
23+
};
24+
var B = (function () {
25+
function B(x) {
26+
}
27+
B.prototype.x = function () { return ""; };
28+
return B;
29+
}());
30+
var C1 = (function (_super) {
31+
__extends(C1, _super);
32+
function C1() {
33+
var _this;
34+
_super.prototype.x.call(_this);
35+
_this = _super.call(this) || this;
36+
return _this;
37+
}
38+
return C1;
39+
}(B));
40+
var C2 = (function (_super) {
41+
__extends(C2, _super);
42+
function C2() {
43+
return _super.call(this, _super.x.call(_this)) || this;
44+
}
45+
return C2;
46+
}(B));

tests/baselines/reference/superWithTypeArgument.errors.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
tests/cases/compiler/superWithTypeArgument.ts(6,5): error TS2377: Constructors for derived classes must contain a 'super' call.
2+
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.
23
tests/cases/compiler/superWithTypeArgument.ts(7,14): error TS1034: 'super' must be followed by an argument list or member access.
34

45

5-
==== tests/cases/compiler/superWithTypeArgument.ts (2 errors) ====
6+
==== tests/cases/compiler/superWithTypeArgument.ts (3 errors) ====
67
class C {
78

89
}
@@ -12,6 +13,8 @@ tests/cases/compiler/superWithTypeArgument.ts(7,14): error TS1034: 'super' must
1213
~~~~~~~~~~~~~~~
1314
super<T>();
1415
~~~~~~~~~~~~~~~~~~~
16+
~~~~~
17+
!!! error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
1518
~
1619
!!! error TS1034: 'super' must be followed by an argument list or member access.
1720
}

0 commit comments

Comments
 (0)