Fix where to report on error. Move from constructor node to just super node

Conflicts:
	src/compiler/checker.ts
This commit is contained in:
Yui T 2015-09-15 16:42:04 -07:00
parent e15eab9d99
commit 653deaa2e2

View File

@ -6848,6 +6848,22 @@ namespace ts {
let container = getThisContainer(node, /* includeArrowFunctions */ true);
let needToCaptureLexicalThis = false;
if (container.kind === SyntaxKind.Constructor) {
// Keep track of whether we have seen "super" before encounter "this" so that
// we can report appropriate error later in checkConstructorDeclaration
// We have to do the check here to make sure we won't give false error when
// "this" is used in arrow functions
// For example:
// constructor() {
// (()=>this); // No Error
// super();
// }
if ((<ConstructorDeclaration>container).hasSeenSuperBeforeThis === undefined) {
(<ConstructorDeclaration>container).hasSeenSuperBeforeThis = false;
}
}
// Now skip arrow functions to get the "real" owner of 'this'.
if (container.kind === SyntaxKind.ArrowFunction) {
container = getThisContainer(container, /* includeArrowFunctions */ false);
@ -6866,11 +6882,6 @@ namespace ts {
// do not return here so in case if lexical this is captured - it will be reflected in flags on NodeLinks
break;
case SyntaxKind.Constructor:
// TODO(yuisu): Comments
if ((<ConstructorDeclaration>container).hasSeenSuperBeforeThis === undefined) {
(<ConstructorDeclaration>container).hasSeenSuperBeforeThis = false;
}
if (isInConstructorArgumentInitializer(node, container)) {
error(node, Diagnostics.this_cannot_be_referenced_in_constructor_arguments);
// do not return here so in case if lexical this is captured - it will be reflected in flags on NodeLinks
@ -11154,8 +11165,25 @@ namespace ts {
const containingClassSymbol = getSymbolOfNode(containingClassDecl);
const containingClassInstanceType = <InterfaceType>getDeclaredTypeOfSymbol(containingClassSymbol);
const baseConstructorType = getBaseConstructorTypeOfClass(containingClassInstanceType);
const statements = (<Block>node.body).statements;
let superCallStatement: ExpressionStatement;
let isSuperCallFirstStatment: boolean;
if (containsSuperCall(node.body)) {
for (const statement of statements) {
if (statement.kind === SyntaxKind.ExpressionStatement && isSuperCallExpression((<ExpressionStatement>statement).expression)) {
superCallStatement = <ExpressionStatement>statement;
if (isSuperCallFirstStatment === undefined) {
isSuperCallFirstStatment = true;
}
}
else if (isSuperCallFirstStatment === undefined && !isPrologueDirective(statement)) {
isSuperCallFirstStatment = false;
}
}
// The main different between looping through each statement in constructor and calling containsSuperCall is that,
// containsSuperCall will consider "super" inside computed-property for inner class declaration
if (superCallStatement || containsSuperCall(node.body)) {
if (baseConstructorType === nullType) {
error(node, Diagnostics.A_constructor_cannot_contain_a_super_call_when_its_class_extends_null);
}
@ -11172,19 +11200,8 @@ namespace ts {
// Skip past any prologue directives to find the first statement
// to ensure that it was a super call.
if (superCallShouldBeFirst) {
const statements = (<Block>node.body).statements;
let superCallStatement: ExpressionStatement;
for (const statement of statements) {
if (statement.kind === SyntaxKind.ExpressionStatement && isSuperCallExpression((<ExpressionStatement>statement).expression)) {
superCallStatement = <ExpressionStatement>statement;
break;
}
if (!isPrologueDirective(statement)) {
break;
}
}
if (!superCallStatement) {
error(node, Diagnostics.A_super_call_must_be_the_first_statement_in_the_constructor_when_a_class_contains_initialized_properties_or_has_parameter_properties);
if (!isSuperCallFirstStatment) {
error(superCallStatement, Diagnostics.A_super_call_must_be_the_first_statement_in_the_constructor_when_a_class_contains_initialized_properties_or_has_parameter_properties);
}
else {
// In such a required super call, it is a compile-time error for argument expressions to reference this.
@ -11192,8 +11209,8 @@ namespace ts {
}
}
else if (!node.hasSeenSuperBeforeThis) {
// TODO: comment
error(node, Diagnostics.super_has_to_be_called_before_this_accessing);
// In ES6, super inside constructor of class-declaration has to precede "this" accessing
error(superCallStatement, Diagnostics.super_has_to_be_called_before_this_accessing);
}
}
else if (baseConstructorType !== nullType) {