diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2ff2c8590d..c37189488b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6436,22 +6436,79 @@ namespace ts { let classType = classDeclaration && 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); } + return unknownType; + } + + if (!canUseSuperExpression) { + if (container && container.kind === SyntaxKind.ComputedPropertyName) { + error(node, Diagnostics.super_cannot_be_referenced_in_a_computed_property_name); + } + else if (isCallExpression) { + error(node, Diagnostics.Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors); + } + else { + error(node, Diagnostics.super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class); + } + 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; + } - 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; + return container.kind === SyntaxKind.Constructor; } else { // TS 1.0 SPEC (April 2014) @@ -6459,75 +6516,28 @@ namespace ts { // - 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; + return 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; + 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; } } } - - 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 (container && container.kind === SyntaxKind.ComputedPropertyName) { - error(node, Diagnostics.super_cannot_be_referenced_in_a_computed_property_name); - } - else if (isCallExpression) { - error(node, Diagnostics.Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors); - } - else { - error(node, Diagnostics.super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class); - } - - return unknownType; + + return false; + } } // Return contextual type of parameter or undefined if no contextual type is available diff --git a/tests/baselines/reference/errorSuperPropertyAccess.js b/tests/baselines/reference/errorSuperPropertyAccess.js index 57a574d8a0..6e35248cd3 100644 --- a/tests/baselines/reference/errorSuperPropertyAccess.js +++ b/tests/baselines/reference/errorSuperPropertyAccess.js @@ -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 diff --git a/tests/baselines/reference/parserSuperExpression1.js b/tests/baselines/reference/parserSuperExpression1.js index 0d312f7910..0d219afad3 100644 --- a/tests/baselines/reference/parserSuperExpression1.js +++ b/tests/baselines/reference/parserSuperExpression1.js @@ -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; })(); diff --git a/tests/baselines/reference/parserSuperExpression2.js b/tests/baselines/reference/parserSuperExpression2.js index 7a77c28ef5..eb3c2c697e 100644 --- a/tests/baselines/reference/parserSuperExpression2.js +++ b/tests/baselines/reference/parserSuperExpression2.js @@ -10,7 +10,7 @@ var C = (function () { function C() { } C.prototype.M = function () { - _super..call(this, 0); + _super.prototype..call(this, 0); }; return C; })(); diff --git a/tests/baselines/reference/parserSuperExpression4.js b/tests/baselines/reference/parserSuperExpression4.js index 46ffc65f57..59ba63bb2c 100644 --- a/tests/baselines/reference/parserSuperExpression4.js +++ b/tests/baselines/reference/parserSuperExpression4.js @@ -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; })(); diff --git a/tests/baselines/reference/super.js b/tests/baselines/reference/super.js index a6b698413e..1d060672ce 100644 --- a/tests/baselines/reference/super.js +++ b/tests/baselines/reference/super.js @@ -79,7 +79,7 @@ var Base2 = (function () { function Base2() { } Base2.prototype.foo = function () { - _super.foo.call(this); + _super.prototype.foo.call(this); }; return Base2; })(); diff --git a/tests/baselines/reference/super1.js b/tests/baselines/reference/super1.js index 6a52cfcd9e..5c2182d8af 100644 --- a/tests/baselines/reference/super1.js +++ b/tests/baselines/reference/super1.js @@ -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; })(); diff --git a/tests/baselines/reference/superCallWithMissingBaseClass.errors.txt b/tests/baselines/reference/superCallWithMissingBaseClass.errors.txt new file mode 100644 index 0000000000..0f4e4b7dd1 --- /dev/null +++ b/tests/baselines/reference/superCallWithMissingBaseClass.errors.txt @@ -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(); + } + } \ No newline at end of file diff --git a/tests/baselines/reference/superCallWithMissingBaseClass.js b/tests/baselines/reference/superCallWithMissingBaseClass.js new file mode 100644 index 0000000000..101e709653 --- /dev/null +++ b/tests/baselines/reference/superCallWithMissingBaseClass.js @@ -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); diff --git a/tests/cases/compiler/superCallWithMissingBaseClass.ts b/tests/cases/compiler/superCallWithMissingBaseClass.ts new file mode 100644 index 0000000000..6f7ede1019 --- /dev/null +++ b/tests/cases/compiler/superCallWithMissingBaseClass.ts @@ -0,0 +1,9 @@ +class Foo extends Bar { + m1() { + return super.m1(); + } + + static m2() { + return super.m2(); + } +} \ No newline at end of file