From 7e1088bb50d9c374a18af14388049fbcae080183 Mon Sep 17 00:00:00 2001 From: Kanchalai Tanglertsampan Date: Wed, 3 Feb 2016 11:51:29 -0800 Subject: [PATCH] Address PR --- src/compiler/checker.ts | 42 ++++++++++++++++++++++++----------------- src/compiler/types.ts | 2 +- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 71cd41522f0..f3273c6e614 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7266,28 +7266,28 @@ namespace ts { return n.kind === SyntaxKind.CallExpression && (n).expression.kind === SyntaxKind.SuperKeyword; } + function findFirstSuperCall(n: Node): Node { + if (isSuperCallExpression(n)) { + return n; + } + else if (isFunctionLike(n)) { + return undefined; + } + return forEachChild(n, findFirstSuperCall); + } + /** * Return a cached result if super-statement is already found. * Otherwise, find a super statement in a given constructor function and cache the result in the node-links of the constructor * * @param constructor constructor-function to look for super statement */ - function getSuperStatementInConstructor(constructor: ConstructorDeclaration): ExpressionStatement { - function getContainingSuperCall(n: Node): Node { - if (isSuperCallExpression(n)) { - return n; - } - else if (isFunctionLike(n)) { - return undefined; - } - return forEachChild(n, getContainingSuperCall); - } - + function getSuperCallInConstructor(constructor: ConstructorDeclaration): ExpressionStatement { const links = getNodeLinks(constructor); - if (!links.superStatement) { - links.superStatement = getContainingSuperCall(constructor.body); + if (!links.superCall) { + links.superCall = findFirstSuperCall(constructor.body); } - return links.superStatement; + return links.superCall; } /** @@ -7316,8 +7316,16 @@ namespace ts { // 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 && !isClassDeclarationExtendNull(containingClassDecl)) { - const superStatement = getSuperStatementInConstructor(container); - if (!superStatement || (superStatement && superStatement.pos > node.pos || superStatement.end > node.pos)) { + const superCall = getSuperCallInConstructor(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); } @@ -11833,7 +11841,7 @@ namespace ts { if (getClassExtendsHeritageClauseElement(containingClassDecl)) { const isClassExtendNull = isClassDeclarationExtendNull(containingClassDecl); - if (getSuperStatementInConstructor(node)) { + if (getSuperCallInConstructor(node)) { if (isClassExtendNull) { error(node, Diagnostics.A_constructor_cannot_contain_a_super_call_when_its_class_extends_null); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 5fdd40c14a1..b99b7a29518 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2088,7 +2088,7 @@ namespace ts { importOnRightSide?: Symbol; // for import declarations - import that appear on the right side jsxFlags?: JsxFlags; // flags for knowning what kind of element/attributes we're dealing with resolvedJsxType?: Type; // resolved element attributes type of a JSX openinglike element - superStatement?: ExpressionStatement; // Cached super-statement found in the constructor. Used in checking whether super is called before this-accessing + superCall?: ExpressionStatement; // Cached first super-call found in the constructor. Used in checking whether super is called before this-accessing } export const enum TypeFlags {