super is only allowed in methods, accessors and constructor
super() is only allowed in a class constructor. super.p is allowed in methods, accessors and constructors. The parser now checks the FunctionState to see what kind of function we are currently inside. BUG=v8:3330 LOG=N R=dslomov@chromium.org, marja@chromium.org Review URL: https://codereview.chromium.org/915563003 Cr-Commit-Position: refs/heads/master@{#26557}
This commit is contained in:
parent
5cd84502bf
commit
9acfd4fe08
@ -217,6 +217,7 @@ class ParserBase : public Traits {
|
|||||||
bool is_generator() const { return IsGeneratorFunction(kind_); }
|
bool is_generator() const { return IsGeneratorFunction(kind_); }
|
||||||
|
|
||||||
FunctionKind kind() const { return kind_; }
|
FunctionKind kind() const { return kind_; }
|
||||||
|
FunctionState* outer() const { return outer_function_state_; }
|
||||||
|
|
||||||
void set_generator_object_variable(
|
void set_generator_object_variable(
|
||||||
typename Traits::Type::GeneratorVariable* variable) {
|
typename Traits::Type::GeneratorVariable* variable) {
|
||||||
@ -249,7 +250,6 @@ class ParserBase : public Traits {
|
|||||||
// for generator functions to have this variable set.
|
// for generator functions to have this variable set.
|
||||||
Variable* generator_object_variable_;
|
Variable* generator_object_variable_;
|
||||||
|
|
||||||
|
|
||||||
FunctionState** function_state_stack_;
|
FunctionState** function_state_stack_;
|
||||||
FunctionState* outer_function_state_;
|
FunctionState* outer_function_state_;
|
||||||
Scope** scope_stack_;
|
Scope** scope_stack_;
|
||||||
@ -569,6 +569,7 @@ class ParserBase : public Traits {
|
|||||||
bool* ok);
|
bool* ok);
|
||||||
ExpressionT ParseTemplateLiteral(ExpressionT tag, int start, bool* ok);
|
ExpressionT ParseTemplateLiteral(ExpressionT tag, int start, bool* ok);
|
||||||
void AddTemplateExpression(ExpressionT);
|
void AddTemplateExpression(ExpressionT);
|
||||||
|
ExpressionT ParseSuperExpression(bool is_new, bool* ok);
|
||||||
|
|
||||||
// Checks if the expression is a valid reference expression (e.g., on the
|
// Checks if the expression is a valid reference expression (e.g., on the
|
||||||
// left-hand side of assignments). Although ruled out by ECMA as early errors,
|
// left-hand side of assignments). Although ruled out by ECMA as early errors,
|
||||||
@ -2666,8 +2667,9 @@ ParserBase<Traits>::ParseMemberWithNewPrefixesExpression(bool* ok) {
|
|||||||
Consume(Token::NEW);
|
Consume(Token::NEW);
|
||||||
int new_pos = position();
|
int new_pos = position();
|
||||||
ExpressionT result = this->EmptyExpression();
|
ExpressionT result = this->EmptyExpression();
|
||||||
if (Check(Token::SUPER)) {
|
if (peek() == Token::SUPER) {
|
||||||
result = this->SuperReference(scope_, factory());
|
const bool is_new = true;
|
||||||
|
result = ParseSuperExpression(is_new, CHECK_OK);
|
||||||
} else {
|
} else {
|
||||||
result = this->ParseMemberWithNewPrefixesExpression(CHECK_OK);
|
result = this->ParseMemberWithNewPrefixesExpression(CHECK_OK);
|
||||||
}
|
}
|
||||||
@ -2724,21 +2726,8 @@ ParserBase<Traits>::ParseMemberExpression(bool* ok) {
|
|||||||
function_token_position, function_type, FunctionLiteral::NORMAL_ARITY,
|
function_token_position, function_type, FunctionLiteral::NORMAL_ARITY,
|
||||||
CHECK_OK);
|
CHECK_OK);
|
||||||
} else if (peek() == Token::SUPER) {
|
} else if (peek() == Token::SUPER) {
|
||||||
int beg_pos = position();
|
const bool is_new = false;
|
||||||
Consume(Token::SUPER);
|
result = ParseSuperExpression(is_new, CHECK_OK);
|
||||||
Token::Value next = peek();
|
|
||||||
if (next == Token::PERIOD || next == Token::LBRACK) {
|
|
||||||
scope_->RecordSuperPropertyUsage();
|
|
||||||
result = this->SuperReference(scope_, factory());
|
|
||||||
} else if (next == Token::LPAREN) {
|
|
||||||
scope_->RecordSuperConstructorCallUsage();
|
|
||||||
result = this->SuperReference(scope_, factory());
|
|
||||||
} else {
|
|
||||||
ReportMessageAt(Scanner::Location(beg_pos, position()),
|
|
||||||
"unexpected_super");
|
|
||||||
*ok = false;
|
|
||||||
return this->EmptyExpression();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
result = ParsePrimaryExpression(CHECK_OK);
|
result = ParsePrimaryExpression(CHECK_OK);
|
||||||
}
|
}
|
||||||
@ -2748,6 +2737,39 @@ ParserBase<Traits>::ParseMemberExpression(bool* ok) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <class Traits>
|
||||||
|
typename ParserBase<Traits>::ExpressionT
|
||||||
|
ParserBase<Traits>::ParseSuperExpression(bool is_new, bool* ok) {
|
||||||
|
int beg_pos = position();
|
||||||
|
Expect(Token::SUPER, CHECK_OK);
|
||||||
|
|
||||||
|
FunctionState* function_state = function_state_;
|
||||||
|
while (IsArrowFunction(function_state->kind())) {
|
||||||
|
function_state = function_state->outer();
|
||||||
|
}
|
||||||
|
// TODO(arv): Handle eval scopes similarly.
|
||||||
|
|
||||||
|
FunctionKind kind = function_state->kind();
|
||||||
|
if (IsConciseMethod(kind) || IsAccessorFunction(kind) ||
|
||||||
|
i::IsConstructor(kind)) {
|
||||||
|
if (peek() == Token::PERIOD || peek() == Token::LBRACK) {
|
||||||
|
scope_->RecordSuperPropertyUsage();
|
||||||
|
return this->SuperReference(scope_, factory());
|
||||||
|
}
|
||||||
|
// new super() is never allowed.
|
||||||
|
// super() is only allowed in constructor
|
||||||
|
if (!is_new && peek() == Token::LPAREN && i::IsConstructor(kind)) {
|
||||||
|
scope_->RecordSuperConstructorCallUsage();
|
||||||
|
return this->SuperReference(scope_, factory());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReportMessageAt(Scanner::Location(beg_pos, position()), "unexpected_super");
|
||||||
|
*ok = false;
|
||||||
|
return this->EmptyExpression();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template <class Traits>
|
template <class Traits>
|
||||||
typename ParserBase<Traits>::ExpressionT
|
typename ParserBase<Traits>::ExpressionT
|
||||||
ParserBase<Traits>::ParseMemberExpressionContinuation(ExpressionT expression,
|
ParserBase<Traits>::ParseMemberExpressionContinuation(ExpressionT expression,
|
||||||
|
@ -954,74 +954,73 @@ TEST(ScopeUsesArgumentsSuperThis) {
|
|||||||
const char* suffix;
|
const char* suffix;
|
||||||
} surroundings[] = {
|
} surroundings[] = {
|
||||||
{ "function f() {", "}" },
|
{ "function f() {", "}" },
|
||||||
{ "var f = () => {", "}" },
|
{ "var f = () => {", "};" },
|
||||||
|
{ "class C { constructor() {", "} }" },
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Expected {
|
enum Expected {
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
ARGUMENTS = 1,
|
ARGUMENTS = 1,
|
||||||
SUPER_PROPERTY = 2,
|
SUPER_PROPERTY = 1 << 1,
|
||||||
SUPER_CONSTRUCTOR_CALL = 4,
|
SUPER_CONSTRUCTOR_CALL = 1 << 2,
|
||||||
THIS = 8,
|
THIS = 1 << 3,
|
||||||
INNER_ARGUMENTS = 16,
|
INNER_ARGUMENTS = 1 << 4,
|
||||||
INNER_SUPER_PROPERTY = 32,
|
INNER_SUPER_PROPERTY = 1 << 5,
|
||||||
INNER_SUPER_CONSTRUCTOR_CALL = 64,
|
INNER_SUPER_CONSTRUCTOR_CALL = 1 << 6,
|
||||||
INNER_THIS = 128
|
INNER_THIS = 1 << 7
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
const char* body;
|
const char* body;
|
||||||
int expected;
|
int expected;
|
||||||
} source_data[] = {
|
} source_data[] = {
|
||||||
{"", NONE},
|
{"", NONE},
|
||||||
{"return this", THIS},
|
{"return this", THIS},
|
||||||
{"return arguments", ARGUMENTS},
|
{"return arguments", ARGUMENTS},
|
||||||
{"return super()", SUPER_CONSTRUCTOR_CALL},
|
{"return super()", SUPER_CONSTRUCTOR_CALL},
|
||||||
{"return super.x", SUPER_PROPERTY},
|
{"return super.x", SUPER_PROPERTY},
|
||||||
{"return arguments[0]", ARGUMENTS},
|
{"return arguments[0]", ARGUMENTS},
|
||||||
{"return this + arguments[0]", ARGUMENTS | THIS},
|
{"return this + arguments[0]", ARGUMENTS | THIS},
|
||||||
{"return this + arguments[0] + super.x",
|
{"return this + arguments[0] + super.x",
|
||||||
ARGUMENTS | SUPER_PROPERTY | THIS},
|
ARGUMENTS | SUPER_PROPERTY | THIS},
|
||||||
{"return x => this + x", INNER_THIS},
|
{"return x => this + x", INNER_THIS},
|
||||||
{"return x => super() + x", INNER_SUPER_CONSTRUCTOR_CALL},
|
{"return x => super() + x", INNER_SUPER_CONSTRUCTOR_CALL},
|
||||||
{"this.foo = 42;", THIS},
|
{"this.foo = 42;", THIS},
|
||||||
{"this.foo();", THIS},
|
{"this.foo();", THIS},
|
||||||
{"if (foo()) { this.f() }", THIS},
|
{"if (foo()) { this.f() }", THIS},
|
||||||
{"if (foo()) { super.f() }", SUPER_PROPERTY},
|
{"if (foo()) { super.f() }", SUPER_PROPERTY},
|
||||||
{"if (arguments.length) { this.f() }", ARGUMENTS | THIS},
|
{"if (arguments.length) { this.f() }", ARGUMENTS | THIS},
|
||||||
{"while (true) { this.f() }", THIS},
|
{"while (true) { this.f() }", THIS},
|
||||||
{"while (true) { super.f() }", SUPER_PROPERTY},
|
{"while (true) { super.f() }", SUPER_PROPERTY},
|
||||||
{"if (true) { while (true) this.foo(arguments) }", ARGUMENTS | THIS},
|
{"if (true) { while (true) this.foo(arguments) }", ARGUMENTS | THIS},
|
||||||
// Multiple nesting levels must work as well.
|
// Multiple nesting levels must work as well.
|
||||||
{"while (true) { while (true) { while (true) return this } }", THIS},
|
{"while (true) { while (true) { while (true) return this } }", THIS},
|
||||||
{"while (true) { while (true) { while (true) return super() } }",
|
{"while (true) { while (true) { while (true) return super() } }",
|
||||||
SUPER_CONSTRUCTOR_CALL},
|
SUPER_CONSTRUCTOR_CALL},
|
||||||
{"if (1) { return () => { while (true) new this() } }", INNER_THIS},
|
{"if (1) { return () => { while (true) new this() } }", INNER_THIS},
|
||||||
{"if (1) { return () => { while (true) new super() } }", NONE},
|
// Note that propagation of the inner_uses_this() value does not
|
||||||
{"if (1) { return () => { while (true) new new super() } }", NONE},
|
// cross boundaries of normal functions onto parent scopes.
|
||||||
// Note that propagation of the inner_uses_this() value does not
|
{"return function (x) { return this + x }", NONE},
|
||||||
// cross boundaries of normal functions onto parent scopes.
|
{"return { m(x) { return super.m() + x } }", NONE},
|
||||||
{"return function (x) { return this + x }", NONE},
|
{"var x = function () { this.foo = 42 };", NONE},
|
||||||
{"return function (x) { return super() + x }", NONE},
|
{"var x = { m() { super.foo = 42 } };", NONE},
|
||||||
{"var x = function () { this.foo = 42 };", NONE},
|
{"if (1) { return function () { while (true) new this() } }", NONE},
|
||||||
{"var x = function () { super.foo = 42 };", NONE},
|
{"if (1) { return { m() { while (true) super.m() } } }", NONE},
|
||||||
{"if (1) { return function () { while (true) new this() } }", NONE},
|
{"return function (x) { return () => this }", NONE},
|
||||||
{"if (1) { return function () { while (true) new super() } }", NONE},
|
{"return { m(x) { return () => super.m() } }", NONE},
|
||||||
{"return function (x) { return () => this }", NONE},
|
// Flags must be correctly set when using block scoping.
|
||||||
{"return function (x) { return () => super() }", NONE},
|
{"\"use strict\"; while (true) { let x; this, arguments; }",
|
||||||
// Flags must be correctly set when using block scoping.
|
INNER_ARGUMENTS | INNER_THIS},
|
||||||
{"\"use strict\"; while (true) { let x; this, arguments; }",
|
{"\"use strict\"; while (true) { let x; this, super(), arguments; }",
|
||||||
INNER_ARGUMENTS | INNER_THIS},
|
INNER_ARGUMENTS | INNER_SUPER_CONSTRUCTOR_CALL | INNER_THIS},
|
||||||
{"\"use strict\"; while (true) { let x; this, super(), arguments; }",
|
{"\"use strict\"; if (foo()) { let x; this.f() }", INNER_THIS},
|
||||||
INNER_ARGUMENTS | INNER_SUPER_CONSTRUCTOR_CALL | INNER_THIS},
|
{"\"use strict\"; if (foo()) { let x; super.f() }",
|
||||||
{"\"use strict\"; if (foo()) { let x; this.f() }", INNER_THIS},
|
INNER_SUPER_PROPERTY},
|
||||||
{"\"use strict\"; if (foo()) { let x; super.f() }",
|
{"\"use strict\"; if (1) {"
|
||||||
INNER_SUPER_PROPERTY},
|
" let x; return { m() { return this + super.m() + arguments } }"
|
||||||
{"\"use strict\"; if (1) {"
|
"}",
|
||||||
" let x; return function () { return this + super() + arguments }"
|
NONE},
|
||||||
"}",
|
};
|
||||||
NONE},
|
|
||||||
};
|
|
||||||
|
|
||||||
i::Isolate* isolate = CcTest::i_isolate();
|
i::Isolate* isolate = CcTest::i_isolate();
|
||||||
i::Factory* factory = isolate->factory();
|
i::Factory* factory = isolate->factory();
|
||||||
@ -1035,6 +1034,15 @@ TEST(ScopeUsesArgumentsSuperThis) {
|
|||||||
|
|
||||||
for (unsigned j = 0; j < arraysize(surroundings); ++j) {
|
for (unsigned j = 0; j < arraysize(surroundings); ++j) {
|
||||||
for (unsigned i = 0; i < arraysize(source_data); ++i) {
|
for (unsigned i = 0; i < arraysize(source_data); ++i) {
|
||||||
|
// Super constructor call is only allowed in constructor.
|
||||||
|
// Super property is only allowed in constructor and method.
|
||||||
|
if (((source_data[i].expected & SUPER_CONSTRUCTOR_CALL) ||
|
||||||
|
(source_data[i].expected & SUPER_PROPERTY) ||
|
||||||
|
(source_data[i].expected & INNER_SUPER_CONSTRUCTOR_CALL) ||
|
||||||
|
(source_data[i].expected & INNER_SUPER_PROPERTY) ||
|
||||||
|
(source_data[i].expected == NONE)) && j != 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
int kProgramByteSize = i::StrLength(surroundings[j].prefix) +
|
int kProgramByteSize = i::StrLength(surroundings[j].prefix) +
|
||||||
i::StrLength(surroundings[j].suffix) +
|
i::StrLength(surroundings[j].suffix) +
|
||||||
i::StrLength(source_data[i].body);
|
i::StrLength(source_data[i].body);
|
||||||
@ -1052,9 +1060,11 @@ TEST(ScopeUsesArgumentsSuperThis) {
|
|||||||
i::Parser parser(&info, &parse_info);
|
i::Parser parser(&info, &parse_info);
|
||||||
parser.set_allow_harmony_arrow_functions(true);
|
parser.set_allow_harmony_arrow_functions(true);
|
||||||
parser.set_allow_harmony_classes(true);
|
parser.set_allow_harmony_classes(true);
|
||||||
|
parser.set_allow_harmony_object_literals(true);
|
||||||
parser.set_allow_harmony_scoping(true);
|
parser.set_allow_harmony_scoping(true);
|
||||||
|
parser.set_allow_harmony_sloppy(true);
|
||||||
info.MarkAsGlobal();
|
info.MarkAsGlobal();
|
||||||
parser.Parse();
|
CHECK(parser.Parse());
|
||||||
CHECK(i::Rewriter::Rewrite(&info));
|
CHECK(i::Rewriter::Rewrite(&info));
|
||||||
CHECK(i::Scope::Analyze(&info));
|
CHECK(i::Scope::Analyze(&info));
|
||||||
CHECK(info.function() != NULL);
|
CHECK(info.function() != NULL);
|
||||||
@ -1064,6 +1074,11 @@ TEST(ScopeUsesArgumentsSuperThis) {
|
|||||||
CHECK_EQ(1, script_scope->inner_scopes()->length());
|
CHECK_EQ(1, script_scope->inner_scopes()->length());
|
||||||
|
|
||||||
i::Scope* scope = script_scope->inner_scopes()->at(0);
|
i::Scope* scope = script_scope->inner_scopes()->at(0);
|
||||||
|
// Adjust for constructor scope.
|
||||||
|
if (j == 2) {
|
||||||
|
CHECK_EQ(1, scope->inner_scopes()->length());
|
||||||
|
scope = scope->inner_scopes()->at(0);
|
||||||
|
}
|
||||||
CHECK_EQ((source_data[i].expected & ARGUMENTS) != 0,
|
CHECK_EQ((source_data[i].expected & ARGUMENTS) != 0,
|
||||||
scope->uses_arguments());
|
scope->uses_arguments());
|
||||||
CHECK_EQ((source_data[i].expected & SUPER_PROPERTY) != 0,
|
CHECK_EQ((source_data[i].expected & SUPER_PROPERTY) != 0,
|
||||||
@ -3637,45 +3652,224 @@ TEST(NoErrorsArrowFunctions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(NoErrorsSuper) {
|
TEST(SuperNoErrors) {
|
||||||
// Tests that parser and preparser accept 'super' keyword in right places.
|
// Tests that parser and preparser accept 'super' keyword in right places.
|
||||||
const char* context_data[][2] = {{"", ";"},
|
const char* context_data[][2] = {
|
||||||
{"k = ", ";"},
|
{"class C { m() { ", "; } }"},
|
||||||
{"foo(", ");"},
|
{"class C { m() { k = ", "; } }"},
|
||||||
{NULL, NULL}};
|
{"class C { m() { foo(", "); } }"},
|
||||||
|
{"class C { m() { () => ", "; } }"},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
const char* statement_data[] = {
|
const char* statement_data[] = {
|
||||||
"super.x",
|
"super.x",
|
||||||
"super[27]",
|
"super[27]",
|
||||||
|
"new super.x",
|
||||||
|
"new super.x()",
|
||||||
|
"new super[27]",
|
||||||
|
"new super[27]()",
|
||||||
|
"z.super", // Ok, property lookup.
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const ParserFlag always_flags[] = {
|
||||||
|
kAllowHarmonyArrowFunctions,
|
||||||
|
kAllowHarmonyClasses,
|
||||||
|
kAllowHarmonyObjectLiterals,
|
||||||
|
kAllowHarmonySloppy
|
||||||
|
};
|
||||||
|
RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
|
||||||
|
always_flags, arraysize(always_flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(SuperErrors) {
|
||||||
|
const char* context_data[][2] = {
|
||||||
|
{"class C { m() { ", "; } }"},
|
||||||
|
{"class C { m() { k = ", "; } }"},
|
||||||
|
{"class C { m() { foo(", "); } }"},
|
||||||
|
{"class C { m() { () => ", "; } }"},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* expression_data[] = {
|
||||||
|
"super",
|
||||||
|
"super = x",
|
||||||
|
"y = super",
|
||||||
|
"f(super)",
|
||||||
"new super",
|
"new super",
|
||||||
"new super()",
|
"new super()",
|
||||||
"new super(12, 45)",
|
"new super(12, 45)",
|
||||||
"new new super",
|
"new new super",
|
||||||
"new new super()",
|
"new new super()",
|
||||||
"new new super()()",
|
"new new super()()",
|
||||||
"z.super", // Ok, property lookup.
|
NULL
|
||||||
NULL};
|
};
|
||||||
|
|
||||||
static const ParserFlag always_flags[] = {kAllowHarmonyClasses};
|
static const ParserFlag always_flags[] = {
|
||||||
RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
|
kAllowHarmonyClasses,
|
||||||
|
kAllowHarmonyObjectLiterals,
|
||||||
|
kAllowHarmonySloppy
|
||||||
|
};
|
||||||
|
RunParserSyncTest(context_data, expression_data, kError, NULL, 0,
|
||||||
always_flags, arraysize(always_flags));
|
always_flags, arraysize(always_flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(ErrorsSuper) {
|
TEST(SuperCall) {
|
||||||
// Tests that parser and preparser generate same errors for 'super'.
|
const char* context_data[][2] = {{"", ""},
|
||||||
const char* context_data[][2] = {{"", ";"},
|
|
||||||
{"k = ", ";"},
|
|
||||||
{"foo(", ");"},
|
|
||||||
{NULL, NULL}};
|
{NULL, NULL}};
|
||||||
|
|
||||||
|
const char* success_data[] = {
|
||||||
|
"class C { constructor() { super(); } }",
|
||||||
|
"class C extends B { constructor() { super(); } }",
|
||||||
|
"class C extends B { constructor() { () => super(); } }",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const ParserFlag always_flags[] = {
|
||||||
|
kAllowHarmonyArrowFunctions,
|
||||||
|
kAllowHarmonyClasses,
|
||||||
|
kAllowHarmonyObjectLiterals,
|
||||||
|
kAllowHarmonySloppy
|
||||||
|
};
|
||||||
|
RunParserSyncTest(context_data, success_data, kSuccess, NULL, 0,
|
||||||
|
always_flags, arraysize(always_flags));
|
||||||
|
|
||||||
|
const char* error_data[] = {
|
||||||
|
"class C { method() { super(); } }",
|
||||||
|
"class C { method() { () => super(); } }",
|
||||||
|
"class C { *method() { super(); } }",
|
||||||
|
"class C { get x() { super(); } }",
|
||||||
|
"class C { set x(_) { super(); } }",
|
||||||
|
"({ method() { super(); } })",
|
||||||
|
"({ *method() { super(); } })",
|
||||||
|
"({ get x() { super(); } })",
|
||||||
|
"({ set x(_) { super(); } })",
|
||||||
|
"({ f: function() { super(); } })",
|
||||||
|
"(function() { super(); })",
|
||||||
|
"var f = function() { super(); }",
|
||||||
|
"({ f: function*() { super(); } })",
|
||||||
|
"(function*() { super(); })",
|
||||||
|
"var f = function*() { super(); }",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
RunParserSyncTest(context_data, error_data, kError, NULL, 0,
|
||||||
|
always_flags, arraysize(always_flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(SuperNewNoErrors) {
|
||||||
|
const char* context_data[][2] = {
|
||||||
|
{"class C { constructor() { ", " } }"},
|
||||||
|
{"class C { *method() { ", " } }"},
|
||||||
|
{"class C { get x() { ", " } }"},
|
||||||
|
{"class C { set x(_) { ", " } }"},
|
||||||
|
{"({ method() { ", " } })"},
|
||||||
|
{"({ *method() { ", " } })"},
|
||||||
|
{"({ get x() { ", " } })"},
|
||||||
|
{"({ set x(_) { ", " } })"},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* expression_data[] = {
|
||||||
|
"new super.x;",
|
||||||
|
"new super.x();",
|
||||||
|
"() => new super.x;",
|
||||||
|
"() => new super.x();",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const ParserFlag always_flags[] = {
|
||||||
|
kAllowHarmonyArrowFunctions,
|
||||||
|
kAllowHarmonyClasses,
|
||||||
|
kAllowHarmonyObjectLiterals,
|
||||||
|
kAllowHarmonySloppy
|
||||||
|
};
|
||||||
|
RunParserSyncTest(context_data, expression_data, kSuccess, NULL, 0,
|
||||||
|
always_flags, arraysize(always_flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(SuperNewErrors) {
|
||||||
|
const char* context_data[][2] = {
|
||||||
|
{"class C { method() { ", " } }"},
|
||||||
|
{"class C { *method() { ", " } }"},
|
||||||
|
{"class C { get x() { ", " } }"},
|
||||||
|
{"class C { set x(_) { ", " } }"},
|
||||||
|
{"({ method() { ", " } })"},
|
||||||
|
{"({ *method() { ", " } })"},
|
||||||
|
{"({ get x() { ", " } })"},
|
||||||
|
{"({ set x(_) { ", " } })"},
|
||||||
|
{"({ f: function() { ", " } })"},
|
||||||
|
{"(function() { ", " })"},
|
||||||
|
{"var f = function() { ", " }"},
|
||||||
|
{"({ f: function*() { ", " } })"},
|
||||||
|
{"(function*() { ", " })"},
|
||||||
|
{"var f = function*() { ", " }"},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
const char* statement_data[] = {
|
const char* statement_data[] = {
|
||||||
|
"new super;",
|
||||||
|
"new super();",
|
||||||
|
"() => new super;",
|
||||||
|
"() => new super();",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const ParserFlag always_flags[] = {
|
||||||
|
kAllowHarmonyArrowFunctions,
|
||||||
|
kAllowHarmonyClasses,
|
||||||
|
kAllowHarmonyObjectLiterals,
|
||||||
|
kAllowHarmonySloppy
|
||||||
|
};
|
||||||
|
RunParserSyncTest(context_data, statement_data, kError, NULL, 0,
|
||||||
|
always_flags, arraysize(always_flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(SuperErrorsNonMethods) {
|
||||||
|
// super is only allowed in methods, accessors and constructors.
|
||||||
|
const char* context_data[][2] = {
|
||||||
|
{"", ";"},
|
||||||
|
{"k = ", ";"},
|
||||||
|
{"foo(", ");"},
|
||||||
|
{"if (", ") {}"},
|
||||||
|
{"if (true) {", "}"},
|
||||||
|
{"if (false) {} else {", "}"},
|
||||||
|
{"while (true) {", "}"},
|
||||||
|
{"function f() {", "}"},
|
||||||
|
{"class C extends (", ") {}"},
|
||||||
|
{"class C { m() { function f() {", "} } }"},
|
||||||
|
{"({ m() { function f() {", "} } })"},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* statement_data[] = {
|
||||||
|
"super",
|
||||||
"super = x",
|
"super = x",
|
||||||
"y = super",
|
"y = super",
|
||||||
"f(super)",
|
"f(super)",
|
||||||
NULL};
|
"super.x",
|
||||||
|
"super[27]",
|
||||||
|
"super.x()",
|
||||||
|
"super[27]()",
|
||||||
|
"super()",
|
||||||
|
"new super.x",
|
||||||
|
"new super.x()",
|
||||||
|
"new super[27]",
|
||||||
|
"new super[27]()",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
static const ParserFlag always_flags[] = {kAllowHarmonyClasses};
|
static const ParserFlag always_flags[] = {
|
||||||
|
kAllowHarmonyClasses,
|
||||||
|
kAllowHarmonyObjectLiterals,
|
||||||
|
kAllowHarmonySloppy
|
||||||
|
};
|
||||||
RunParserSyncTest(context_data, statement_data, kError, NULL, 0,
|
RunParserSyncTest(context_data, statement_data, kError, NULL, 0,
|
||||||
always_flags, arraysize(always_flags));
|
always_flags, arraysize(always_flags));
|
||||||
}
|
}
|
||||||
|
@ -874,10 +874,4 @@ function assertAccessorDescriptor(object, name) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
new C3();
|
new C3();
|
||||||
|
|
||||||
class C4 extends Object {
|
|
||||||
constructor() {
|
|
||||||
super(new super());
|
|
||||||
}
|
|
||||||
}; new C4();
|
|
||||||
}());
|
}());
|
||||||
|
@ -22,15 +22,6 @@
|
|||||||
set accessor(v) {
|
set accessor(v) {
|
||||||
super.accessor = v;
|
super.accessor = v;
|
||||||
},
|
},
|
||||||
property: function() {
|
|
||||||
super.property();
|
|
||||||
},
|
|
||||||
propertyWithParen: (function() {
|
|
||||||
super.property();
|
|
||||||
}),
|
|
||||||
propertyWithParens: ((function() {
|
|
||||||
super.property();
|
|
||||||
})),
|
|
||||||
|
|
||||||
methodNoSuper() {},
|
methodNoSuper() {},
|
||||||
get getterNoSuper() {},
|
get getterNoSuper() {},
|
||||||
@ -50,9 +41,6 @@
|
|||||||
desc = Object.getOwnPropertyDescriptor(object, 'accessor');
|
desc = Object.getOwnPropertyDescriptor(object, 'accessor');
|
||||||
assertEquals(object, desc.get[%HomeObjectSymbol()]);
|
assertEquals(object, desc.get[%HomeObjectSymbol()]);
|
||||||
assertEquals(object, desc.set[%HomeObjectSymbol()]);
|
assertEquals(object, desc.set[%HomeObjectSymbol()]);
|
||||||
assertEquals(object, object.property[%HomeObjectSymbol()]);
|
|
||||||
assertEquals(object, object.propertyWithParen[%HomeObjectSymbol()]);
|
|
||||||
assertEquals(object, object.propertyWithParens[%HomeObjectSymbol()]);
|
|
||||||
|
|
||||||
assertEquals(undefined, object.methodNoSuper[%HomeObjectSymbol()]);
|
assertEquals(undefined, object.methodNoSuper[%HomeObjectSymbol()]);
|
||||||
desc = Object.getOwnPropertyDescriptor(object, 'getterNoSuper');
|
desc = Object.getOwnPropertyDescriptor(object, 'getterNoSuper');
|
||||||
@ -118,21 +106,6 @@
|
|||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
||||||
(function TestMethodAsProperty() {
|
|
||||||
var object = {
|
|
||||||
__proto__: {
|
|
||||||
method: function(x) {
|
|
||||||
return 'proto' + x;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
method: function(x) {
|
|
||||||
return super.method(x);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
assertEquals('proto42', object.method(42));
|
|
||||||
})();
|
|
||||||
|
|
||||||
|
|
||||||
(function TestOptimized() {
|
(function TestOptimized() {
|
||||||
// Object literals without any accessors get optimized.
|
// Object literals without any accessors get optimized.
|
||||||
var object = {
|
var object = {
|
||||||
@ -154,15 +127,7 @@
|
|||||||
*g() {
|
*g() {
|
||||||
yield super.m();
|
yield super.m();
|
||||||
},
|
},
|
||||||
g2: function*() {
|
|
||||||
yield super.m() + 1;
|
|
||||||
},
|
|
||||||
g3: (function*() {
|
|
||||||
yield super.m() + 2;
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
assertEquals(42, o.g().next().value);
|
assertEquals(42, o.g().next().value);
|
||||||
assertEquals(43, o.g2().next().value);
|
|
||||||
assertEquals(44, o.g3().next().value);
|
|
||||||
})();
|
})();
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -117,6 +117,7 @@
|
|||||||
|
|
||||||
# TODO(arv): TurboFan does not yet add [[HomeObject]] as needed.
|
# TODO(arv): TurboFan does not yet add [[HomeObject]] as needed.
|
||||||
'harmony/object-literals-super': [PASS, NO_VARIANTS],
|
'harmony/object-literals-super': [PASS, NO_VARIANTS],
|
||||||
|
'harmony/super': [PASS, NO_VARIANTS],
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
# Too slow in debug mode with --stress-opt mode.
|
# Too slow in debug mode with --stress-opt mode.
|
||||||
|
Loading…
Reference in New Issue
Block a user