Merge pull request #4121 from Microsoft/NodeFlagsOnSuperCall
always set NodeCheckFlags when checking super expression
This commit is contained in:
commit
4c7b214a69
10 changed files with 144 additions and 80 deletions
|
@ -6436,6 +6436,39 @@ namespace ts {
|
|||
let classType = classDeclaration && <InterfaceType>getDeclaredTypeOfSymbol(getSymbolOfNode(classDeclaration));
|
||||
let baseClassType = classType && getBaseTypes(classType)[0];
|
||||
|
||||
let container = getSuperContainer(node, /*includeFunctions*/ true);
|
||||
let needToCaptureLexicalThis = false;
|
||||
|
||||
if (!isCallExpression) {
|
||||
// adjust the container reference in case if super is used inside arrow functions with arbitrary deep nesting
|
||||
while (container && container.kind === SyntaxKind.ArrowFunction) {
|
||||
container = getSuperContainer(container, /*includeFunctions*/ true);
|
||||
needToCaptureLexicalThis = languageVersion < ScriptTarget.ES6;
|
||||
}
|
||||
}
|
||||
|
||||
let canUseSuperExpression = isLegalUsageOfSuperExpression(container);
|
||||
let nodeCheckFlag: NodeCheckFlags = 0;
|
||||
|
||||
// always set NodeCheckFlags for 'super' expression node
|
||||
if (canUseSuperExpression) {
|
||||
if ((container.flags & NodeFlags.Static) || isCallExpression) {
|
||||
nodeCheckFlag = NodeCheckFlags.SuperStatic;
|
||||
}
|
||||
else {
|
||||
nodeCheckFlag = NodeCheckFlags.SuperInstance;
|
||||
}
|
||||
|
||||
getNodeLinks(node).flags |= nodeCheckFlag;
|
||||
|
||||
if (needToCaptureLexicalThis) {
|
||||
// call expressions are allowed only in constructors so they should always capture correct 'this'
|
||||
// super property access expressions can also appear in arrow functions -
|
||||
// in this case they should also use correct lexical this
|
||||
captureLexicalThis(node.parent, container);
|
||||
}
|
||||
}
|
||||
|
||||
if (!baseClassType) {
|
||||
if (!classDeclaration || !getClassExtendsHeritageClauseElement(classDeclaration)) {
|
||||
error(node, Diagnostics.super_can_only_be_referenced_in_a_derived_class);
|
||||
|
@ -6443,80 +6476,7 @@ namespace ts {
|
|||
return unknownType;
|
||||
}
|
||||
|
||||
let container = getSuperContainer(node, /*includeFunctions*/ true);
|
||||
|
||||
if (container) {
|
||||
let canUseSuperExpression = false;
|
||||
let needToCaptureLexicalThis: boolean;
|
||||
if (isCallExpression) {
|
||||
// TS 1.0 SPEC (April 2014): 4.8.1
|
||||
// Super calls are only permitted in constructors of derived classes
|
||||
canUseSuperExpression = container.kind === SyntaxKind.Constructor;
|
||||
}
|
||||
else {
|
||||
// TS 1.0 SPEC (April 2014)
|
||||
// 'super' property access is allowed
|
||||
// - In a constructor, instance member function, instance member accessor, or instance member variable initializer where this references a derived class instance
|
||||
// - In a static member function or static member accessor
|
||||
|
||||
// super property access might appear in arrow functions with arbitrary deep nesting
|
||||
needToCaptureLexicalThis = false;
|
||||
while (container && container.kind === SyntaxKind.ArrowFunction) {
|
||||
container = getSuperContainer(container, /*includeFunctions*/ true);
|
||||
needToCaptureLexicalThis = languageVersion < ScriptTarget.ES6;
|
||||
}
|
||||
|
||||
// topmost container must be something that is directly nested in the class declaration
|
||||
if (container && isClassLike(container.parent)) {
|
||||
if (container.flags & NodeFlags.Static) {
|
||||
canUseSuperExpression =
|
||||
container.kind === SyntaxKind.MethodDeclaration ||
|
||||
container.kind === SyntaxKind.MethodSignature ||
|
||||
container.kind === SyntaxKind.GetAccessor ||
|
||||
container.kind === SyntaxKind.SetAccessor;
|
||||
}
|
||||
else {
|
||||
canUseSuperExpression =
|
||||
container.kind === SyntaxKind.MethodDeclaration ||
|
||||
container.kind === SyntaxKind.MethodSignature ||
|
||||
container.kind === SyntaxKind.GetAccessor ||
|
||||
container.kind === SyntaxKind.SetAccessor ||
|
||||
container.kind === SyntaxKind.PropertyDeclaration ||
|
||||
container.kind === SyntaxKind.PropertySignature ||
|
||||
container.kind === SyntaxKind.Constructor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (canUseSuperExpression) {
|
||||
let returnType: Type;
|
||||
|
||||
if ((container.flags & NodeFlags.Static) || isCallExpression) {
|
||||
getNodeLinks(node).flags |= NodeCheckFlags.SuperStatic;
|
||||
returnType = getBaseConstructorTypeOfClass(classType);
|
||||
}
|
||||
else {
|
||||
getNodeLinks(node).flags |= NodeCheckFlags.SuperInstance;
|
||||
returnType = baseClassType;
|
||||
}
|
||||
|
||||
if (container.kind === SyntaxKind.Constructor && isInConstructorArgumentInitializer(node, container)) {
|
||||
// issue custom error message for super property access in constructor arguments (to be aligned with old compiler)
|
||||
error(node, Diagnostics.super_cannot_be_referenced_in_constructor_arguments);
|
||||
returnType = unknownType;
|
||||
}
|
||||
|
||||
if (!isCallExpression && needToCaptureLexicalThis) {
|
||||
// call expressions are allowed only in constructors so they should always capture correct 'this'
|
||||
// super property access expressions can also appear in arrow functions -
|
||||
// in this case they should also use correct lexical this
|
||||
captureLexicalThis(node.parent, container);
|
||||
}
|
||||
|
||||
return returnType;
|
||||
}
|
||||
}
|
||||
|
||||
if (!canUseSuperExpression) {
|
||||
if (container && container.kind === SyntaxKind.ComputedPropertyName) {
|
||||
error(node, Diagnostics.super_cannot_be_referenced_in_a_computed_property_name);
|
||||
}
|
||||
|
@ -6530,6 +6490,56 @@ namespace ts {
|
|||
return unknownType;
|
||||
}
|
||||
|
||||
if (container.kind === SyntaxKind.Constructor && isInConstructorArgumentInitializer(node, container)) {
|
||||
// issue custom error message for super property access in constructor arguments (to be aligned with old compiler)
|
||||
error(node, Diagnostics.super_cannot_be_referenced_in_constructor_arguments);
|
||||
return unknownType;
|
||||
}
|
||||
|
||||
return nodeCheckFlag === NodeCheckFlags.SuperStatic
|
||||
? getBaseConstructorTypeOfClass(classType)
|
||||
: baseClassType;
|
||||
|
||||
function isLegalUsageOfSuperExpression(container: Node): boolean {
|
||||
if (!container) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isCallExpression) {
|
||||
// TS 1.0 SPEC (April 2014): 4.8.1
|
||||
// Super calls are only permitted in constructors of derived classes
|
||||
return container.kind === SyntaxKind.Constructor;
|
||||
}
|
||||
else {
|
||||
// TS 1.0 SPEC (April 2014)
|
||||
// 'super' property access is allowed
|
||||
// - In a constructor, instance member function, instance member accessor, or instance member variable initializer where this references a derived class instance
|
||||
// - In a static member function or static member accessor
|
||||
|
||||
// topmost container must be something that is directly nested in the class declaration
|
||||
if (container && isClassLike(container.parent)) {
|
||||
if (container.flags & NodeFlags.Static) {
|
||||
return container.kind === SyntaxKind.MethodDeclaration ||
|
||||
container.kind === SyntaxKind.MethodSignature ||
|
||||
container.kind === SyntaxKind.GetAccessor ||
|
||||
container.kind === SyntaxKind.SetAccessor;
|
||||
}
|
||||
else {
|
||||
return container.kind === SyntaxKind.MethodDeclaration ||
|
||||
container.kind === SyntaxKind.MethodSignature ||
|
||||
container.kind === SyntaxKind.GetAccessor ||
|
||||
container.kind === SyntaxKind.SetAccessor ||
|
||||
container.kind === SyntaxKind.PropertyDeclaration ||
|
||||
container.kind === SyntaxKind.PropertySignature ||
|
||||
container.kind === SyntaxKind.Constructor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Return contextual type of parameter or undefined if no contextual type is available
|
||||
function getContextuallyTypedParameterType(parameter: ParameterDeclaration): Type {
|
||||
if (isFunctionExpressionOrArrowFunction(parameter.parent)) {
|
||||
|
|
|
@ -139,14 +139,14 @@ var __extends = (this && this.__extends) || function (d, b) {
|
|||
//super property access in instance member accessor(get and set) of class with no base type
|
||||
var NoBase = (function () {
|
||||
function NoBase() {
|
||||
this.m = _super.prototype;
|
||||
this.n = _super.hasOwnProperty.call(this, '');
|
||||
var a = _super.prototype;
|
||||
var b = _super.hasOwnProperty.call(this, '');
|
||||
this.m = _super.prototype.prototype;
|
||||
this.n = _super.prototype.hasOwnProperty.call(this, '');
|
||||
var a = _super.prototype.prototype;
|
||||
var b = _super.prototype.hasOwnProperty.call(this, '');
|
||||
}
|
||||
NoBase.prototype.fn = function () {
|
||||
var a = _super.prototype;
|
||||
var b = _super.hasOwnProperty.call(this, '');
|
||||
var a = _super.prototype.prototype;
|
||||
var b = _super.prototype.hasOwnProperty.call(this, '');
|
||||
};
|
||||
//super static property access in static member function of class with no base type
|
||||
//super static property access in static member accessor(get and set) of class with no base type
|
||||
|
|
|
@ -18,7 +18,7 @@ var C = (function () {
|
|||
function C() {
|
||||
}
|
||||
C.prototype.foo = function () {
|
||||
_super.foo.call(this);
|
||||
_super.prototype.foo.call(this);
|
||||
};
|
||||
return C;
|
||||
})();
|
||||
|
@ -30,7 +30,7 @@ var M1;
|
|||
function C() {
|
||||
}
|
||||
C.prototype.foo = function () {
|
||||
_super.foo.call(this);
|
||||
_super.prototype.foo.call(this);
|
||||
};
|
||||
return C;
|
||||
})();
|
||||
|
|
|
@ -10,7 +10,7 @@ var C = (function () {
|
|||
function C() {
|
||||
}
|
||||
C.prototype.M = function () {
|
||||
_super..call(this, 0);
|
||||
_super.prototype..call(this, 0);
|
||||
};
|
||||
return C;
|
||||
})();
|
||||
|
|
|
@ -18,7 +18,7 @@ var C = (function () {
|
|||
function C() {
|
||||
}
|
||||
C.prototype.foo = function () {
|
||||
_super.foo = 1;
|
||||
_super.prototype.foo = 1;
|
||||
};
|
||||
return C;
|
||||
})();
|
||||
|
@ -30,7 +30,7 @@ var M1;
|
|||
function C() {
|
||||
}
|
||||
C.prototype.foo = function () {
|
||||
_super.foo = 1;
|
||||
_super.prototype.foo = 1;
|
||||
};
|
||||
return C;
|
||||
})();
|
||||
|
|
|
@ -79,7 +79,7 @@ var Base2 = (function () {
|
|||
function Base2() {
|
||||
}
|
||||
Base2.prototype.foo = function () {
|
||||
_super.foo.call(this);
|
||||
_super.prototype.foo.call(this);
|
||||
};
|
||||
return Base2;
|
||||
})();
|
||||
|
|
|
@ -165,7 +165,7 @@ var Base4;
|
|||
function Sub4E() {
|
||||
}
|
||||
Sub4E.prototype.x = function () {
|
||||
return _super.x.call(this);
|
||||
return _super.prototype.x.call(this);
|
||||
};
|
||||
return Sub4E;
|
||||
})();
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
tests/cases/compiler/superCallWithMissingBaseClass.ts(1,19): error TS2304: Cannot find name 'Bar'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/superCallWithMissingBaseClass.ts (1 errors) ====
|
||||
class Foo extends Bar {
|
||||
~~~
|
||||
!!! error TS2304: Cannot find name 'Bar'.
|
||||
m1() {
|
||||
return super.m1();
|
||||
}
|
||||
|
||||
static m2() {
|
||||
return super.m2();
|
||||
}
|
||||
}
|
30
tests/baselines/reference/superCallWithMissingBaseClass.js
Normal file
30
tests/baselines/reference/superCallWithMissingBaseClass.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
//// [superCallWithMissingBaseClass.ts]
|
||||
class Foo extends Bar {
|
||||
m1() {
|
||||
return super.m1();
|
||||
}
|
||||
|
||||
static m2() {
|
||||
return super.m2();
|
||||
}
|
||||
}
|
||||
|
||||
//// [superCallWithMissingBaseClass.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 Foo = (function (_super) {
|
||||
__extends(Foo, _super);
|
||||
function Foo() {
|
||||
_super.apply(this, arguments);
|
||||
}
|
||||
Foo.prototype.m1 = function () {
|
||||
return _super.prototype.m1.call(this);
|
||||
};
|
||||
Foo.m2 = function () {
|
||||
return _super.m2.call(this);
|
||||
};
|
||||
return Foo;
|
||||
})(Bar);
|
9
tests/cases/compiler/superCallWithMissingBaseClass.ts
Normal file
9
tests/cases/compiler/superCallWithMissingBaseClass.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
class Foo extends Bar {
|
||||
m1() {
|
||||
return super.m1();
|
||||
}
|
||||
|
||||
static m2() {
|
||||
return super.m2();
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue