Skip to content

Commit 4c7b214

Browse files
committed
Merge pull request #4121 from Microsoft/NodeFlagsOnSuperCall
always set NodeCheckFlags when checking super expression
2 parents a4a1a51 + 24c8a8e commit 4c7b214

10 files changed

+144
-80
lines changed

src/compiler/checker.ts

Lines changed: 77 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -6436,98 +6436,108 @@ namespace ts {
64366436
let classType = classDeclaration && <InterfaceType>getDeclaredTypeOfSymbol(getSymbolOfNode(classDeclaration));
64376437
let baseClassType = classType && getBaseTypes(classType)[0];
64386438

6439+
let container = getSuperContainer(node, /*includeFunctions*/ true);
6440+
let needToCaptureLexicalThis = false;
6441+
6442+
if (!isCallExpression) {
6443+
// adjust the container reference in case if super is used inside arrow functions with arbitrary deep nesting
6444+
while (container && container.kind === SyntaxKind.ArrowFunction) {
6445+
container = getSuperContainer(container, /*includeFunctions*/ true);
6446+
needToCaptureLexicalThis = languageVersion < ScriptTarget.ES6;
6447+
}
6448+
}
6449+
6450+
let canUseSuperExpression = isLegalUsageOfSuperExpression(container);
6451+
let nodeCheckFlag: NodeCheckFlags = 0;
6452+
6453+
// always set NodeCheckFlags for 'super' expression node
6454+
if (canUseSuperExpression) {
6455+
if ((container.flags & NodeFlags.Static) || isCallExpression) {
6456+
nodeCheckFlag = NodeCheckFlags.SuperStatic;
6457+
}
6458+
else {
6459+
nodeCheckFlag = NodeCheckFlags.SuperInstance;
6460+
}
6461+
6462+
getNodeLinks(node).flags |= nodeCheckFlag;
6463+
6464+
if (needToCaptureLexicalThis) {
6465+
// call expressions are allowed only in constructors so they should always capture correct 'this'
6466+
// super property access expressions can also appear in arrow functions -
6467+
// in this case they should also use correct lexical this
6468+
captureLexicalThis(node.parent, container);
6469+
}
6470+
}
6471+
64396472
if (!baseClassType) {
64406473
if (!classDeclaration || !getClassExtendsHeritageClauseElement(classDeclaration)) {
64416474
error(node, Diagnostics.super_can_only_be_referenced_in_a_derived_class);
64426475
}
6476+
return unknownType;
6477+
}
6478+
6479+
if (!canUseSuperExpression) {
6480+
if (container && container.kind === SyntaxKind.ComputedPropertyName) {
6481+
error(node, Diagnostics.super_cannot_be_referenced_in_a_computed_property_name);
6482+
}
6483+
else if (isCallExpression) {
6484+
error(node, Diagnostics.Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors);
6485+
}
6486+
else {
6487+
error(node, Diagnostics.super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class);
6488+
}
6489+
64436490
return unknownType;
64446491
}
6492+
6493+
if (container.kind === SyntaxKind.Constructor && isInConstructorArgumentInitializer(node, container)) {
6494+
// issue custom error message for super property access in constructor arguments (to be aligned with old compiler)
6495+
error(node, Diagnostics.super_cannot_be_referenced_in_constructor_arguments);
6496+
return unknownType;
6497+
}
6498+
6499+
return nodeCheckFlag === NodeCheckFlags.SuperStatic
6500+
? getBaseConstructorTypeOfClass(classType)
6501+
: baseClassType;
6502+
6503+
function isLegalUsageOfSuperExpression(container: Node): boolean {
6504+
if (!container) {
6505+
return false;
6506+
}
64456507

6446-
let container = getSuperContainer(node, /*includeFunctions*/ true);
6447-
6448-
if (container) {
6449-
let canUseSuperExpression = false;
6450-
let needToCaptureLexicalThis: boolean;
64516508
if (isCallExpression) {
64526509
// TS 1.0 SPEC (April 2014): 4.8.1
64536510
// Super calls are only permitted in constructors of derived classes
6454-
canUseSuperExpression = container.kind === SyntaxKind.Constructor;
6511+
return container.kind === SyntaxKind.Constructor;
64556512
}
64566513
else {
64576514
// TS 1.0 SPEC (April 2014)
64586515
// 'super' property access is allowed
64596516
// - In a constructor, instance member function, instance member accessor, or instance member variable initializer where this references a derived class instance
64606517
// - In a static member function or static member accessor
64616518

6462-
// super property access might appear in arrow functions with arbitrary deep nesting
6463-
needToCaptureLexicalThis = false;
6464-
while (container && container.kind === SyntaxKind.ArrowFunction) {
6465-
container = getSuperContainer(container, /*includeFunctions*/ true);
6466-
needToCaptureLexicalThis = languageVersion < ScriptTarget.ES6;
6467-
}
6468-
64696519
// topmost container must be something that is directly nested in the class declaration
64706520
if (container && isClassLike(container.parent)) {
64716521
if (container.flags & NodeFlags.Static) {
6472-
canUseSuperExpression =
6473-
container.kind === SyntaxKind.MethodDeclaration ||
6474-
container.kind === SyntaxKind.MethodSignature ||
6475-
container.kind === SyntaxKind.GetAccessor ||
6476-
container.kind === SyntaxKind.SetAccessor;
6522+
return container.kind === SyntaxKind.MethodDeclaration ||
6523+
container.kind === SyntaxKind.MethodSignature ||
6524+
container.kind === SyntaxKind.GetAccessor ||
6525+
container.kind === SyntaxKind.SetAccessor;
64776526
}
64786527
else {
6479-
canUseSuperExpression =
6480-
container.kind === SyntaxKind.MethodDeclaration ||
6481-
container.kind === SyntaxKind.MethodSignature ||
6482-
container.kind === SyntaxKind.GetAccessor ||
6483-
container.kind === SyntaxKind.SetAccessor ||
6484-
container.kind === SyntaxKind.PropertyDeclaration ||
6485-
container.kind === SyntaxKind.PropertySignature ||
6486-
container.kind === SyntaxKind.Constructor;
6528+
return container.kind === SyntaxKind.MethodDeclaration ||
6529+
container.kind === SyntaxKind.MethodSignature ||
6530+
container.kind === SyntaxKind.GetAccessor ||
6531+
container.kind === SyntaxKind.SetAccessor ||
6532+
container.kind === SyntaxKind.PropertyDeclaration ||
6533+
container.kind === SyntaxKind.PropertySignature ||
6534+
container.kind === SyntaxKind.Constructor;
64876535
}
64886536
}
64896537
}
6490-
6491-
if (canUseSuperExpression) {
6492-
let returnType: Type;
6493-
6494-
if ((container.flags & NodeFlags.Static) || isCallExpression) {
6495-
getNodeLinks(node).flags |= NodeCheckFlags.SuperStatic;
6496-
returnType = getBaseConstructorTypeOfClass(classType);
6497-
}
6498-
else {
6499-
getNodeLinks(node).flags |= NodeCheckFlags.SuperInstance;
6500-
returnType = baseClassType;
6501-
}
6502-
6503-
if (container.kind === SyntaxKind.Constructor && isInConstructorArgumentInitializer(node, container)) {
6504-
// issue custom error message for super property access in constructor arguments (to be aligned with old compiler)
6505-
error(node, Diagnostics.super_cannot_be_referenced_in_constructor_arguments);
6506-
returnType = unknownType;
6507-
}
6508-
6509-
if (!isCallExpression && needToCaptureLexicalThis) {
6510-
// call expressions are allowed only in constructors so they should always capture correct 'this'
6511-
// super property access expressions can also appear in arrow functions -
6512-
// in this case they should also use correct lexical this
6513-
captureLexicalThis(node.parent, container);
6514-
}
6515-
6516-
return returnType;
6517-
}
6518-
}
6519-
6520-
if (container && container.kind === SyntaxKind.ComputedPropertyName) {
6521-
error(node, Diagnostics.super_cannot_be_referenced_in_a_computed_property_name);
6522-
}
6523-
else if (isCallExpression) {
6524-
error(node, Diagnostics.Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors);
6525-
}
6526-
else {
6527-
error(node, Diagnostics.super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class);
6528-
}
6529-
6530-
return unknownType;
6538+
6539+
return false;
6540+
}
65316541
}
65326542

65336543
// Return contextual type of parameter or undefined if no contextual type is available

tests/baselines/reference/errorSuperPropertyAccess.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -139,14 +139,14 @@ var __extends = (this && this.__extends) || function (d, b) {
139139
//super property access in instance member accessor(get and set) of class with no base type
140140
var NoBase = (function () {
141141
function NoBase() {
142-
this.m = _super.prototype;
143-
this.n = _super.hasOwnProperty.call(this, '');
144-
var a = _super.prototype;
145-
var b = _super.hasOwnProperty.call(this, '');
142+
this.m = _super.prototype.prototype;
143+
this.n = _super.prototype.hasOwnProperty.call(this, '');
144+
var a = _super.prototype.prototype;
145+
var b = _super.prototype.hasOwnProperty.call(this, '');
146146
}
147147
NoBase.prototype.fn = function () {
148-
var a = _super.prototype;
149-
var b = _super.hasOwnProperty.call(this, '');
148+
var a = _super.prototype.prototype;
149+
var b = _super.prototype.hasOwnProperty.call(this, '');
150150
};
151151
//super static property access in static member function of class with no base type
152152
//super static property access in static member accessor(get and set) of class with no base type

tests/baselines/reference/parserSuperExpression1.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ var C = (function () {
1818
function C() {
1919
}
2020
C.prototype.foo = function () {
21-
_super.foo.call(this);
21+
_super.prototype.foo.call(this);
2222
};
2323
return C;
2424
})();
@@ -30,7 +30,7 @@ var M1;
3030
function C() {
3131
}
3232
C.prototype.foo = function () {
33-
_super.foo.call(this);
33+
_super.prototype.foo.call(this);
3434
};
3535
return C;
3636
})();

tests/baselines/reference/parserSuperExpression2.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ var C = (function () {
1010
function C() {
1111
}
1212
C.prototype.M = function () {
13-
_super..call(this, 0);
13+
_super.prototype..call(this, 0);
1414
};
1515
return C;
1616
})();

tests/baselines/reference/parserSuperExpression4.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ var C = (function () {
1818
function C() {
1919
}
2020
C.prototype.foo = function () {
21-
_super.foo = 1;
21+
_super.prototype.foo = 1;
2222
};
2323
return C;
2424
})();
@@ -30,7 +30,7 @@ var M1;
3030
function C() {
3131
}
3232
C.prototype.foo = function () {
33-
_super.foo = 1;
33+
_super.prototype.foo = 1;
3434
};
3535
return C;
3636
})();

tests/baselines/reference/super.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ var Base2 = (function () {
7979
function Base2() {
8080
}
8181
Base2.prototype.foo = function () {
82-
_super.foo.call(this);
82+
_super.prototype.foo.call(this);
8383
};
8484
return Base2;
8585
})();

tests/baselines/reference/super1.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ var Base4;
165165
function Sub4E() {
166166
}
167167
Sub4E.prototype.x = function () {
168-
return _super.x.call(this);
168+
return _super.prototype.x.call(this);
169169
};
170170
return Sub4E;
171171
})();
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
tests/cases/compiler/superCallWithMissingBaseClass.ts(1,19): error TS2304: Cannot find name 'Bar'.
2+
3+
4+
==== tests/cases/compiler/superCallWithMissingBaseClass.ts (1 errors) ====
5+
class Foo extends Bar {
6+
~~~
7+
!!! error TS2304: Cannot find name 'Bar'.
8+
m1() {
9+
return super.m1();
10+
}
11+
12+
static m2() {
13+
return super.m2();
14+
}
15+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//// [superCallWithMissingBaseClass.ts]
2+
class Foo extends Bar {
3+
m1() {
4+
return super.m1();
5+
}
6+
7+
static m2() {
8+
return super.m2();
9+
}
10+
}
11+
12+
//// [superCallWithMissingBaseClass.js]
13+
var __extends = (this && this.__extends) || function (d, b) {
14+
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
15+
function __() { this.constructor = d; }
16+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
17+
};
18+
var Foo = (function (_super) {
19+
__extends(Foo, _super);
20+
function Foo() {
21+
_super.apply(this, arguments);
22+
}
23+
Foo.prototype.m1 = function () {
24+
return _super.prototype.m1.call(this);
25+
};
26+
Foo.m2 = function () {
27+
return _super.m2.call(this);
28+
};
29+
return Foo;
30+
})(Bar);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
class Foo extends Bar {
2+
m1() {
3+
return super.m1();
4+
}
5+
6+
static m2() {
7+
return super.m2();
8+
}
9+
}

0 commit comments

Comments
 (0)