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:
arv 2015-02-10 11:51:18 -08:00 committed by Commit bot
parent 5cd84502bf
commit 9acfd4fe08
6 changed files with 1407 additions and 1228 deletions

View File

@ -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,

View File

@ -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));
} }

View File

@ -874,10 +874,4 @@ function assertAccessorDescriptor(object, name) {
} }
}; };
new C3(); new C3();
class C4 extends Object {
constructor() {
super(new super());
}
}; new C4();
}()); }());

View File

@ -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

View File

@ -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.