Commit 77394fa0 authored by conradw's avatar conradw Committed by Commit bot

[parser] disallow language mode directive in body of function with non-simple parameters

TC39 agreed to disallow "use strict" directives in function body when
non-simple parameter lists are used.

This is a continuation of caitp's CL https://codereview.chromium.org/1281163002/
with some refactorings removed for now.

Still TODO: there is a lot of duplication between the is_simple field of
FormalParametersBase and the NonSimpleParameter property ExpressionClassifier
keeps track of. It should be possible to remove the former with a minor
refactoring of arrow function parsing. This will be attempted in a follow-up CL.

BUG=
LOG=N

Review URL: https://codereview.chromium.org/1300103005

Cr-Commit-Position: refs/heads/master@{#30388}
parent aca4a411
......@@ -45,11 +45,17 @@ class ExpressionClassifier {
ArrowFormalParametersProduction)
};
enum FunctionProperties { NonSimpleParameter = 1 << 0 };
ExpressionClassifier()
: invalid_productions_(0), duplicate_finder_(nullptr) {}
: invalid_productions_(0),
function_properties_(0),
duplicate_finder_(nullptr) {}
explicit ExpressionClassifier(DuplicateFinder* duplicate_finder)
: invalid_productions_(0), duplicate_finder_(duplicate_finder) {}
: invalid_productions_(0),
function_properties_(0),
duplicate_finder_(duplicate_finder) {}
bool is_valid(unsigned productions) const {
return (invalid_productions_ & productions) == 0;
......@@ -111,6 +117,14 @@ class ExpressionClassifier {
return strong_mode_formal_parameter_error_;
}
bool is_simple_parameter_list() const {
return !(function_properties_ & NonSimpleParameter);
}
void RecordNonSimpleParameter() {
function_properties_ |= NonSimpleParameter;
}
void RecordExpressionError(const Scanner::Location& loc,
MessageTemplate::Template message,
const char* arg = nullptr) {
......@@ -216,15 +230,21 @@ class ExpressionClassifier {
// As an exception to the above, the result continues to be a valid arrow
// formal parameters if the inner expression is a valid binding pattern.
if (productions & ArrowFormalParametersProduction &&
is_valid_arrow_formal_parameters() &&
!inner.is_valid_binding_pattern()) {
is_valid_arrow_formal_parameters()) {
// Also copy function properties if expecting an arrow function
// parameter.
function_properties_ |= inner.function_properties_;
if (!inner.is_valid_binding_pattern()) {
invalid_productions_ |= ArrowFormalParametersProduction;
arrow_formal_parameters_error_ = inner.binding_pattern_error_;
}
}
}
private:
unsigned invalid_productions_;
unsigned function_properties_;
Error expression_error_;
Error binding_pattern_error_;
Error assignment_pattern_error_;
......
......@@ -296,6 +296,8 @@ class CallSite {
T(IllegalAccess, "Illegal access") \
T(IllegalBreak, "Illegal break statement") \
T(IllegalContinue, "Illegal continue statement") \
T(IllegalLanguageModeDirective, \
"Illegal '%' directive in function with non-simple parameter list") \
T(IllegalReturn, "Illegal return statement") \
T(InvalidLhsInAssignment, "Invalid left-hand side in assignment") \
T(InvalidLhsInFor, "Invalid left-hand side in for-loop") \
......
......@@ -1198,8 +1198,7 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
// BindingIdentifier
ParseFormalParameter(&formals, &formals_classifier, &ok);
if (ok) {
DeclareFormalParameter(
formals.scope, formals.at(0), formals.is_simple,
DeclareFormalParameter(formals.scope, formals.at(0),
&formals_classifier);
}
}
......@@ -1322,6 +1321,20 @@ void* Parser::ParseStatementList(ZoneList<Statement*>* body, int end_token,
token_loc.end_pos - token_loc.beg_pos ==
ast_value_factory()->use_strong_string()->length() + 2;
if (use_strict_found || use_strong_found) {
if (!scope_->HasSimpleParameters()) {
// TC39 deemed "use strict" directives to be an error when occurring
// in the body of a function with non-simple parameter list, on
// 29/7/2015. https://goo.gl/ueA7Ln
//
// In V8, this also applies to "use strong " directives.
const AstRawString* string = literal->raw_value()->AsString();
ParserTraits::ReportMessageAt(
token_loc, MessageTemplate::kIllegalLanguageModeDirective,
string);
*ok = false;
return nullptr;
}
// Strong mode implies strict mode. If there are several "use strict"
// / "use strong" directives, do the strict mode changes only once.
if (is_sloppy(scope_->language_mode())) {
......@@ -3889,8 +3902,7 @@ Handle<FixedArray> CompileTimeValue::GetElements(Handle<FixedArray> value) {
void ParserTraits::ParseArrowFunctionFormalParameters(
ParserFormalParameters* parameters, Expression* expr,
const Scanner::Location& params_loc,
Scanner::Location* duplicate_loc, bool* ok) {
const Scanner::Location& params_loc, bool* ok) {
if (parameters->Arity() >= Code::kMaxArguments) {
ReportMessageAt(params_loc, MessageTemplate::kMalformedArrowFunParamList);
*ok = false;
......@@ -3917,8 +3929,7 @@ void ParserTraits::ParseArrowFunctionFormalParameters(
DCHECK_EQ(binop->op(), Token::COMMA);
Expression* left = binop->left();
Expression* right = binop->right();
ParseArrowFunctionFormalParameters(parameters, left, params_loc,
duplicate_loc, ok);
ParseArrowFunctionFormalParameters(parameters, left, params_loc, ok);
if (!*ok) return;
// LHS of comma expression should be unparenthesized.
expr = right;
......@@ -3962,15 +3973,16 @@ void ParserTraits::ParseArrowFunctionFormalParameterList(
Scanner::Location* duplicate_loc, bool* ok) {
if (expr->IsEmptyParentheses()) return;
ParseArrowFunctionFormalParameters(parameters, expr, params_loc,
duplicate_loc, ok);
ParseArrowFunctionFormalParameters(parameters, expr, params_loc, ok);
if (!*ok) return;
ExpressionClassifier classifier;
if (!parameters->is_simple) {
classifier.RecordNonSimpleParameter();
}
for (int i = 0; i < parameters->Arity(); ++i) {
auto parameter = parameters->at(i);
ExpressionClassifier classifier;
DeclareFormalParameter(
parameters->scope, parameter, parameters->is_simple, &classifier);
DeclareFormalParameter(parameters->scope, parameter, &classifier);
if (!duplicate_loc->IsValid()) {
*duplicate_loc = classifier.duplicate_formal_parameter_error().location;
}
......@@ -4585,7 +4597,8 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
#undef SET_ALLOW
}
PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction(
language_mode(), function_state_->kind(), logger, bookmark);
language_mode(), function_state_->kind(), scope_->has_simple_parameters(),
logger, bookmark);
if (pre_parse_timer_ != NULL) {
pre_parse_timer_->Stop();
}
......
......@@ -786,11 +786,11 @@ class ParserTraits {
Expression* initializer, bool is_rest);
V8_INLINE void DeclareFormalParameter(
Scope* scope, const ParserFormalParameters::Parameter& parameter,
bool is_simple, ExpressionClassifier* classifier);
void ParseArrowFunctionFormalParameters(
ParserFormalParameters* parameters, Expression* params,
ExpressionClassifier* classifier);
void ParseArrowFunctionFormalParameters(ParserFormalParameters* parameters,
Expression* params,
const Scanner::Location& params_loc,
Scanner::Location* duplicate_loc, bool* ok);
bool* ok);
void ParseArrowFunctionFormalParameterList(
ParserFormalParameters* parameters, Expression* params,
const Scanner::Location& params_loc,
......@@ -1335,12 +1335,14 @@ void ParserTraits::AddFormalParameter(
void ParserTraits::DeclareFormalParameter(
Scope* scope, const ParserFormalParameters::Parameter& parameter,
bool is_simple, ExpressionClassifier* classifier) {
ExpressionClassifier* classifier) {
bool is_duplicate = false;
bool is_simple = classifier->is_simple_parameter_list();
// TODO(caitp): Remove special handling for rest once desugaring is in.
auto name = is_simple || parameter.is_rest
? parameter.name : parser_->ast_value_factory()->empty_string();
auto mode = is_simple || parameter.is_rest ? VAR : TEMPORARY;
if (!is_simple) scope->SetHasNonSimpleParameters();
bool is_optional = parameter.initializer != nullptr;
Variable* var = scope->DeclareParameter(
name, mode, is_optional, parameter.is_rest, &is_duplicate);
......
......@@ -102,8 +102,8 @@ PreParserExpression PreParserTraits::ParseFunctionLiteral(
PreParser::PreParseResult PreParser::PreParseLazyFunction(
LanguageMode language_mode, FunctionKind kind, ParserRecorder* log,
Scanner::BookmarkScope* bookmark) {
LanguageMode language_mode, FunctionKind kind, bool has_simple_parameters,
ParserRecorder* log, Scanner::BookmarkScope* bookmark) {
log_ = log;
// Lazy functions always have trivial outer scopes (no with/catch scopes).
Scope* top_scope = NewScope(scope_, SCRIPT_SCOPE);
......@@ -113,6 +113,7 @@ PreParser::PreParseResult PreParser::PreParseLazyFunction(
scope_->SetLanguageMode(language_mode);
Scope* function_scope = NewScope(
scope_, IsArrowFunction(kind) ? ARROW_SCOPE : FUNCTION_SCOPE, kind);
if (!has_simple_parameters) function_scope->SetHasNonSimpleParameters();
PreParserFactory function_factory(NULL);
FunctionState function_state(&function_state_, &scope_, function_scope, kind,
&function_factory);
......@@ -251,15 +252,33 @@ void PreParser::ParseStatementList(int end_token, bool* ok,
}
if (directive_prologue) {
if (statement.IsUseStrictLiteral()) {
bool use_strict_found = statement.IsUseStrictLiteral();
bool use_strong_found =
statement.IsUseStrongLiteral() && allow_strong_mode();
if (use_strict_found) {
scope_->SetLanguageMode(
static_cast<LanguageMode>(scope_->language_mode() | STRICT));
} else if (statement.IsUseStrongLiteral() && allow_strong_mode()) {
} else if (use_strong_found) {
scope_->SetLanguageMode(static_cast<LanguageMode>(
scope_->language_mode() | STRONG));
} else if (!statement.IsStringLiteral()) {
directive_prologue = false;
}
if ((use_strict_found || use_strong_found) &&
!scope_->HasSimpleParameters()) {
// TC39 deemed "use strict" directives to be an error when occurring
// in the body of a function with non-simple parameter list, on
// 29/7/2015. https://goo.gl/ueA7Ln
//
// In V8, this also applies to "use strong " directives.
PreParserTraits::ReportMessageAt(
token_loc, MessageTemplate::kIllegalLanguageModeDirective,
use_strict_found ? "use strict" : "use strong");
*ok = false;
return;
}
}
// If we're allowed to reset to a bookmark, we will do so when we see a long
......@@ -1057,7 +1076,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
Expect(Token::LPAREN, CHECK_OK);
int start_position = scanner()->location().beg_pos;
function_scope->set_start_position(start_position);
PreParserFormalParameters formals(nullptr);
PreParserFormalParameters formals(function_scope);
ParseFormalParameterList(&formals, &formals_classifier, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
int formals_end_position = scanner()->location().end_pos;
......
......@@ -1648,8 +1648,11 @@ class PreParserTraits {
++parameters->arity;
}
void DeclareFormalParameter(Scope* scope, PreParserIdentifier parameter,
bool is_simple,
ExpressionClassifier* classifier) {}
ExpressionClassifier* classifier) {
if (!classifier->is_simple_parameter_list()) {
scope->SetHasNonSimpleParameters();
}
}
void CheckConflictingVarDeclarations(Scope* scope, bool* ok) {}
......@@ -1747,8 +1750,8 @@ class PreParser : public ParserBase<PreParserTraits> {
// At return, unless an error occurred, the scanner is positioned before the
// the final '}'.
PreParseResult PreParseLazyFunction(
LanguageMode language_mode, FunctionKind kind, ParserRecorder* log,
Scanner::BookmarkScope* bookmark = nullptr);
LanguageMode language_mode, FunctionKind kind, bool has_simple_parameters,
ParserRecorder* log, Scanner::BookmarkScope* bookmark = nullptr);
private:
friend class PreParserTraits;
......@@ -2283,6 +2286,7 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
classifier->RecordExpressionError(scanner()->location(),
MessageTemplate::kUnexpectedToken,
Token::String(Token::ELLIPSIS));
classifier->RecordNonSimpleParameter();
Scanner::Location expr_loc = scanner()->peek_location();
Token::Value tok = peek();
result = this->ParseAssignmentExpression(true, classifier, CHECK_OK);
......@@ -2295,6 +2299,7 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
return this->EmptyExpression();
}
result = factory()->NewSpread(result, ellipsis_pos);
if (peek() == Token::COMMA) {
ReportMessageAt(scanner()->peek_location(),
MessageTemplate::kParamAfterRest);
......@@ -2385,6 +2390,7 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression(
this->ParseAssignmentExpression(accept_IN, &binding_classifier, CHECK_OK);
classifier->Accumulate(binding_classifier,
ExpressionClassifier::AllProductions);
bool is_simple_parameter_list = this->IsIdentifier(result);
bool seen_rest = false;
while (peek() == Token::COMMA) {
if (seen_rest) {
......@@ -2408,10 +2414,15 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression(
ExpressionT right = this->ParseAssignmentExpression(
accept_IN, &binding_classifier, CHECK_OK);
if (is_rest) right = factory()->NewSpread(right, pos);
is_simple_parameter_list =
is_simple_parameter_list && this->IsIdentifier(right);
classifier->Accumulate(binding_classifier,
ExpressionClassifier::AllProductions);
result = factory()->NewBinaryOperation(Token::COMMA, result, right, pos);
}
if (!is_simple_parameter_list || seen_rest) {
classifier->RecordNonSimpleParameter();
}
return result;
}
......@@ -2839,7 +2850,6 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
}
ExpressionT expression = this->ParseConditionalExpression(
accept_IN, &arrow_formals_classifier, CHECK_OK);
if (allow_harmony_arrow_functions() && peek() == Token::ARROW) {
BindingPatternUnexpectedToken(classifier);
ValidateArrowFormalParameters(&arrow_formals_classifier, expression,
......@@ -2848,6 +2858,10 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
Scope* scope =
this->NewScope(scope_, ARROW_SCOPE, FunctionKind::kArrowFunction);
FormalParametersT parameters(scope);
if (!arrow_formals_classifier.is_simple_parameter_list()) {
scope->SetHasNonSimpleParameters();
parameters.is_simple = false;
}
checkpoint.Restore(&parameters.materialized_literals_count);
scope->set_start_position(lhs_beg_pos);
......@@ -3662,6 +3676,7 @@ void ParserBase<Traits>::ParseFormalParameter(
return;
}
parameters->is_simple = false;
classifier->RecordNonSimpleParameter();
}
ExpressionT initializer = Traits::EmptyExpression();
......@@ -3672,6 +3687,7 @@ void ParserBase<Traits>::ParseFormalParameter(
ValidateExpression(&init_classifier, ok);
if (!*ok) return;
parameters->is_simple = false;
classifier->RecordNonSimpleParameter();
}
Traits::AddFormalParameter(parameters, pattern, initializer, is_rest);
......@@ -3712,6 +3728,7 @@ void ParserBase<Traits>::ParseFormalParameterList(
if (parameters->has_rest) {
parameters->is_simple = false;
classifier->RecordNonSimpleParameter();
if (peek() == Token::COMMA) {
ReportMessageAt(scanner()->peek_location(),
MessageTemplate::kParamAfterRest);
......@@ -3723,8 +3740,7 @@ void ParserBase<Traits>::ParseFormalParameterList(
for (int i = 0; i < parameters->Arity(); ++i) {
auto parameter = parameters->at(i);
Traits::DeclareFormalParameter(
parameters->scope, parameter, parameters->is_simple, classifier);
Traits::DeclareFormalParameter(parameters->scope, parameter, classifier);
}
}
......
......@@ -475,7 +475,6 @@ Variable* Scope::DeclareParameter(
Variable* var;
if (mode == TEMPORARY) {
var = NewTemporary(name);
has_simple_parameters_ = false;
} else {
var = variables_.Declare(this, name, mode, Variable::NORMAL,
kCreatedInitialized);
......@@ -489,7 +488,6 @@ Variable* Scope::DeclareParameter(
DCHECK_NULL(rest_parameter_);
rest_parameter_ = var;
rest_index_ = num_parameters();
has_simple_parameters_ = false;
}
params_.Add(var, zone());
return var;
......
......@@ -387,10 +387,25 @@ class Scope: public ZoneObject {
}
bool has_simple_parameters() const {
DCHECK(is_function_scope());
return has_simple_parameters_;
}
// TODO(caitp): manage this state in a better way. PreParser must be able to
// communicate that the scope is non-simple, without allocating any parameters
// as the Parser does. This is necessary to ensure that TC39's proposed early
// error can be reported consistently regardless of whether lazily parsed or
// not.
void SetHasNonSimpleParameters() {
DCHECK(is_function_scope());
has_simple_parameters_ = false;
}
// Retrieve `IsSimpleParameterList` of current or outer function.
bool HasSimpleParameters() {
Scope* scope = ClosureScope();
return !scope->is_function_scope() || scope->has_simple_parameters();
}
// The local variable 'arguments' if we need to allocate it; NULL otherwise.
Variable* arguments() const {
DCHECK(!is_arrow_scope() || arguments_ == nullptr);
......
......@@ -6925,3 +6925,90 @@ TEST(LetSloppy) {
RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
arraysize(always_flags));
}
TEST(LanguageModeDirectivesNonSimpleParameterListErrors) {
// TC39 deemed "use strict" directives to be an error when occurring in the
// body of a function with non-simple parameter list, on 29/7/2015.
// https://goo.gl/ueA7Ln
//
// In V8, this also applies to "use strong " directives.
const char* context_data[][2] = {
{"function f(", ") { 'use strict'; }"},
{"function f(", ") { 'use strong'; }"},
{"function* g(", ") { 'use strict'; }"},
{"function* g(", ") { 'use strong'; }"},
{"class c { foo(", ") { 'use strict' }"},
{"class c { foo(", ") { 'use strong' }"},
{"var a = (", ") => { 'use strict'; }"},
{"var a = (", ") => { 'use strong'; }"},
{"var o = { m(", ") { 'use strict'; }"},
{"var o = { m(", ") { 'use strong'; }"},
{"var o = { *gm(", ") { 'use strict'; }"},
{"var o = { *gm(", ") { 'use strong'; }"},
{"var c = { m(", ") { 'use strict'; }"},
{"var c = { m(", ") { 'use strong'; }"},
{"var c = { *gm(", ") { 'use strict'; }"},
{"var c = { *gm(", ") { 'use strong'; }"},
{"'use strict'; function f(", ") { 'use strict'; }"},
{"'use strict'; function f(", ") { 'use strong'; }"},
{"'use strict'; function* g(", ") { 'use strict'; }"},
{"'use strict'; function* g(", ") { 'use strong'; }"},
{"'use strict'; class c { foo(", ") { 'use strict' }"},
{"'use strict'; class c { foo(", ") { 'use strong' }"},
{"'use strict'; var a = (", ") => { 'use strict'; }"},
{"'use strict'; var a = (", ") => { 'use strong'; }"},
{"'use strict'; var o = { m(", ") { 'use strict'; }"},
{"'use strict'; var o = { m(", ") { 'use strong'; }"},
{"'use strict'; var o = { *gm(", ") { 'use strict'; }"},
{"'use strict'; var o = { *gm(", ") { 'use strong'; }"},
{"'use strict'; var c = { m(", ") { 'use strict'; }"},
{"'use strict'; var c = { m(", ") { 'use strong'; }"},
{"'use strict'; var c = { *gm(", ") { 'use strict'; }"},
{"'use strict'; var c = { *gm(", ") { 'use strong'; }"},
{"'use strong'; function f(", ") { 'use strict'; }"},
{"'use strong'; function f(", ") { 'use strong'; }"},
{"'use strong'; function* g(", ") { 'use strict'; }"},
{"'use strong'; function* g(", ") { 'use strong'; }"},
{"'use strong'; class c { foo(", ") { 'use strict' }"},
{"'use strong'; class c { foo(", ") { 'use strong' }"},
{"'use strong'; var a = (", ") => { 'use strict'; }"},
{"'use strong'; var a = (", ") => { 'use strong'; }"},
{"'use strong'; var o = { m(", ") { 'use strict'; }"},
{"'use strong'; var o = { m(", ") { 'use strong'; }"},
{"'use strong'; var o = { *gm(", ") { 'use strict'; }"},
{"'use strong'; var o = { *gm(", ") { 'use strong'; }"},
{"'use strong'; var c = { m(", ") { 'use strict'; }"},
{"'use strong'; var c = { m(", ") { 'use strong'; }"},
{"'use strong'; var c = { *gm(", ") { 'use strict'; }"},
{"'use strong'; var c = { *gm(", ") { 'use strong'; }"},
{NULL, NULL}};
const char* data[] = {
// TODO(@caitp): support formal parameter initializers
"{}",
"[]",
"[{}]",
"{a}",
"a, {b}",
"a, b, {c, d, e}",
"initializer = true",
"a, b, c = 1",
"...args",
"a, b, ...rest",
"[a, b, ...rest]",
"{ bindingPattern = {} }",
"{ initializedBindingPattern } = { initializedBindingPattern: true }",
NULL};
static const ParserFlag always_flags[] = {
kAllowHarmonyArrowFunctions, kAllowHarmonyDefaultParameters,
kAllowHarmonyDestructuring, kAllowHarmonyRestParameters,
kAllowHarmonySloppy, kAllowStrongMode
};
RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
arraysize(always_flags));
}
......@@ -18,8 +18,9 @@
//
// strictTest(6,5,4,3,2,1)
//
var strictTest = (a, b, ...c) => {
var strictTest = (() => {
"use strict";
return (a, b, ...c) => {
assertEquals(Array, c.constructor);
assertTrue(Array.isArray(c));
......@@ -29,7 +30,8 @@ var strictTest = (a, b, ...c) => {
for (var i = 2; i < a; ++i) {
assertEquals(c[i - 2], a - i);
}
}
};
})();
var sloppyTest = (a, b, ...c) => {
assertEquals(Array, c.constructor);
......
......@@ -81,85 +81,92 @@
})();
(function TestParameterScoping() {
(function TestParameterScopingSloppy() {
var x = 1;
function f1(a = x) { var x = 2; return a; }
assertEquals(1, f1());
function f2(a = x) { function x() {}; return a; }
assertEquals(1, f2());
function f3(a = x) { 'use strict'; let x = 2; return a; }
function f3(a = eval("x")) { var x; return a; }
assertEquals(1, f3());
function f4(a = x) { 'use strict'; const x = 2; return a; }
function f31(a = eval("'use strict'; x")) { var x; return a; }
assertEquals(1, f31());
function f4(a = function() { return x }) { var x; return a(); }
assertEquals(1, f4());
function f5(a = x) { 'use strict'; function x() {}; return a; }
function f5(a = () => x) { var x; return a(); }
assertEquals(1, f5());
function f6(a = eval("x")) { var x; return a; }
function f6(a = () => eval("x")) { var x; return a(); }
assertEquals(1, f6());
function f61(a = eval("x")) { 'use strict'; var x; return a; }
function f61(a = () => { 'use strict'; return eval("x") }) { var x; return a(); }
assertEquals(1, f61());
function f62(a = eval("'use strict'; x")) { var x; return a; }
function f62(a = () => eval("'use strict'; x")) { var x; return a(); }
assertEquals(1, f62());
function f7(a = function() { return x }) { var x; return a(); }
assertEquals(1, f7());
function f8(a = () => x) { var x; return a(); }
assertEquals(1, f8());
function f9(a = () => eval("x")) { var x; return a(); }
assertEquals(1, f9());
function f91(a = () => eval("x")) { 'use strict'; var x; return a(); }
assertEquals(1, f91());
function f92(a = () => { 'use strict'; return eval("x") }) { var x; return a(); }
assertEquals(1, f92());
function f93(a = () => eval("'use strict'; x")) { var x; return a(); }
assertEquals(1, f93());
var g1 = (a = x) => { var x = 2; return a; };
assertEquals(1, g1());
var g2 = (a = x) => { function x() {}; return a; };
assertEquals(1, g2());
var g3 = (a = x) => { 'use strict'; let x = 2; return a; };
var g3 = (a = eval("x")) => { var x; return a; };
assertEquals(1, g3());
var g4 = (a = x) => { 'use strict'; const x = 2; return a; };
var g31 = (a = eval("'use strict'; x")) => { var x; return a; };
assertEquals(1, g31());
var g4 = (a = function() { return x }) => { var x; return a(); };
assertEquals(1, g4());
var g5 = (a = x) => { 'use strict'; function x() {}; return a; };
var g5 = (a = () => x) => { var x; return a(); };
assertEquals(1, g5());
var g6 = (a = eval("x")) => { var x; return a; };
var g6 = (a = () => eval("x")) => { var x; return a(); };
assertEquals(1, g6());
var g61 = (a = eval("x")) => { 'use strict'; var x; return a; };
var g61 = (a = () => { 'use strict'; return eval("x") }) => { var x; return a(); };
assertEquals(1, g61());
var g62 = (a = eval("'use strict'; x")) => { var x; return a; };
var g62 = (a = () => eval("'use strict'; x")) => { var x; return a(); };
assertEquals(1, g62());
var g7 = (a = function() { return x }) => { var x; return a(); };
assertEquals(1, g7());
var g8 = (a = () => x) => { var x; return a(); };
assertEquals(1, g8());
var g9 = (a = () => eval("x")) => { var x; return a(); };
assertEquals(1, g9());
var g91 = (a = () => eval("x")) => { 'use strict'; var x; return a(); };
assertEquals(1, g91());
var g92 = (a = () => { 'use strict'; return eval("x") }) => { var x; return a(); };
assertEquals(1, g92());
var g93 = (a = () => eval("'use strict'; x")) => { var x; return a(); };
assertEquals(1, g93());
var f11 = function f(x = f) { var f; return x; }
assertSame(f11, f11());
var f12 = function f(x = f) { function f() {}; return x; }
assertSame(f12, f12());
var f13 = function f(x = f) { 'use strict'; let f; return x; }
assertSame(f13, f13());
var f14 = function f(x = f) { 'use strict'; const f = 0; return x; }
assertSame(f14, f14());
var f15 = function f(x = f) { 'use strict'; function f() {}; return x; }
assertSame(f15, f15());
var f16 = function f(f = 7, x = f) { return x; }
assertSame(7, f16());
var f13 = function f(f = 7, x = f) { return x; }
assertSame(7, f13());
var o1 = {f: function(x = this) { return x; }};
assertSame(o1, o1.f());
assertSame(1, o1.f(1));
})();
(function TestParameterScopingStrict() {
"use strict";
var x = 1;
function f1(a = x) { let x = 2; return a; }
assertEquals(1, f1());
function f2(a = x) { const x = 2; return a; }
assertEquals(1, f2());
function f3(a = x) { function x() {}; return a; }
assertEquals(1, f3());
function f4(a = eval("x")) { var x; return a; }
assertEquals(1, f4());
function f5(a = () => eval("x")) { var x; return a(); }
assertEquals(1, f5());
var g1 = (a = x) => { let x = 2; return a; };
assertEquals(1, g1());
var g2 = (a = x) => { const x = 2; return a; };
assertEquals(1, g2());
var g3 = (a = x) => { function x() {}; return a; };
assertEquals(1, g3());
var g4 = (a = eval("x")) => { var x; return a; };
assertEquals(1, g4());
var g5 = (a = () => eval("x")) => { var x; return a(); };
assertEquals(1, g5());
var f11 = function f(x = f) { let f; return x; }
assertSame(f11, f11());
var f12 = function f(x = f) { const f = 0; return x; }
assertSame(f12, f12());
var f13 = function f(x = f) { function f() {}; return x; }
assertSame(f13, f13());
})();
(function TestSloppyEvalScoping() {
var x = 1;
......@@ -342,29 +349,22 @@
assertEquals(3, f22(() => 3));
})();
(function TestParameterTDZ() {
(function TestParameterTDZSloppy() {
function f1(a = x, x) { return a }
assertThrows(() => f1(undefined, 4), ReferenceError);
assertEquals(4, f1(4, 5));
function f2(a = eval("x"), x) { return a }
assertThrows(() => f2(undefined, 4), ReferenceError);
assertEquals(4, f2(4, 5));
function f3(a = eval("x"), x) { 'use strict'; return a }
function f3(a = eval("'use strict'; x"), x) { return a }
assertThrows(() => f3(undefined, 4), ReferenceError);
assertEquals(4, f3(4, 5));
function f4(a = eval("'use strict'; x"), x) { return a }
assertThrows(() => f4(undefined, 4), ReferenceError);
assertEquals(4, f4(4, 5));
function f5(a = () => x, x) { return a() }
function f4(a = () => x, x) { return a() }
assertEquals(4, f4(() => 4, 5));
function f5(a = () => eval("x"), x) { return a() }
assertEquals(4, f5(() => 4, 5));
function f6(a = () => eval("x"), x) { return a() }
function f6(a = () => eval("'use strict'; x"), x) { return a() }
assertEquals(4, f6(() => 4, 5));
function f7(a = () => eval("x"), x) { 'use strict'; return a() }
assertEquals(4, f7(() => 4, 5));
function f8(a = () => eval("'use strict'; x"), x) { return a() }
assertEquals(4, f8(() => 4, 5));
function f11(a = x, x = 2) { return a }
assertThrows(() => f11(), ReferenceError);
......@@ -376,36 +376,49 @@
assertThrows(() => f12(undefined), ReferenceError);
assertThrows(() => f12(undefined, 4), ReferenceError);
assertEquals(4, f12(4, 5));
function f13(a = eval("x"), x = 2) { 'use strict'; return a }
function f13(a = eval("'use strict'; x"), x = 2) { return a }
assertThrows(() => f13(), ReferenceError);
assertThrows(() => f13(undefined), ReferenceError);
assertThrows(() => f13(undefined, 4), ReferenceError);
assertEquals(4, f13(4, 5));
function f14(a = eval("'use strict'; x"), x = 2) { return a }
assertThrows(() => f14(), ReferenceError);
assertThrows(() => f14(undefined), ReferenceError);
assertThrows(() => f14(undefined, 4), ReferenceError);
assertEquals(4, f14(4, 5));
function f34(x = function() { return a }, ...a) { return x()[0] }
assertEquals(4, f34(undefined, 4));
function f35(x = () => a, ...a) { return x()[0] }
assertEquals(4, f35(undefined, 4));
function f36(x = () => eval("a"), ...a) { return x()[0] }
assertEquals(4, f36(undefined, 4));
function f37(x = () => eval("a"), ...a) { 'use strict'; return x()[0] }
assertEquals(4, f37(undefined, 4));
function f38(x = () => { 'use strict'; return eval("a") }, ...a) { return x()[0] }
assertEquals(4, f38(undefined, 4));
function f39(x = () => eval("'use strict'; a"), ...a) { return x()[0] }
assertEquals(4, f39(undefined, 4));
var g34 = (x = function() { return a }, ...a) => { return x()[0] };
assertEquals(4, g34(undefined, 4));
var g35 = (x = () => a, ...a) => { return x()[0] };
assertEquals(4, g35(undefined, 4));
function f21(x = function() { return a }, ...a) { return x()[0] }
assertEquals(4, f21(undefined, 4));
function f22(x = () => a, ...a) { return x()[0] }
assertEquals(4, f22(undefined, 4));
function f23(x = () => eval("a"), ...a) { return x()[0] }
assertEquals(4, f23(undefined, 4));
function f24(x = () => {'use strict'; return eval("a") }, ...a) {
return x()[0]
}
assertEquals(4, f24(undefined, 4));
function f25(x = () => eval("'use strict'; a"), ...a) { return x()[0] }
assertEquals(4, f25(undefined, 4));
var g1 = (x = function() { return a }, ...a) => { return x()[0] };
assertEquals(4, g1(undefined, 4));
var g2 = (x = () => a, ...a) => { return x()[0] };
assertEquals(4, g2(undefined, 4));
})();
(function TestParameterTDZStrict() {
"use strict";
function f1(a = eval("x"), x) { return a }
assertThrows(() => f1(undefined, 4), ReferenceError);
assertEquals(4, f1(4, 5));
function f2(a = () => eval("x"), x) { return a() }
assertEquals(4, f2(() => 4, 5));
function f11(a = eval("x"), x = 2) { return a }
assertThrows(() => f11(), ReferenceError);
assertThrows(() => f11(undefined), ReferenceError);
assertThrows(() => f11(undefined, 4), ReferenceError);
assertEquals(4, f11(4, 5));
function f21(x = () => eval("a"), ...a) { return x()[0] }
assertEquals(4, f21(undefined, 4));
})();
(function TestArgumentsForNonSimpleParameters() {
function f1(x = 900) { arguments[0] = 1; return x }
......@@ -429,3 +442,18 @@
assertEquals(1, (function(x, y = 1, z, v = 2) {}).length);
assertEquals(1, (function(x, y = 1, z, v = 2, ...a) {}).length);
})();
(function TestDirectiveThrows() {
"use strict";
assertThrows(function(){ eval("function(x=1){'use strict';}") }, SyntaxError);
assertThrows(function(){ eval("(x=1) => {'use strict';}") }, SyntaxError);
assertThrows(
function(){ eval("(class{foo(x=1) {'use strict';}});") }, SyntaxError);
assertThrows(
function(){ eval("function(a, x=1){'use strict';}") }, SyntaxError);
assertThrows(function(){ eval("(a, x=1) => {'use strict';}") }, SyntaxError);
assertThrows(
function(){ eval("(class{foo(a, x=1) {'use strict';}});") }, SyntaxError);
})();
......@@ -741,16 +741,22 @@
assertEquals(1, f1({}));
function f2({a = x}) { function x() {}; return a; }
assertEquals(1, f2({}));
function f3({a = x}) { 'use strict'; let x = 2; return a; }
(function() {
'use strict';
function f3({a = x}) { let x = 2; return a; }
assertEquals(1, f3({}));
function f4({a = x}) { 'use strict'; const x = 2; return a; }
function f4({a = x}) { const x = 2; return a; }
assertEquals(1, f4({}));
function f5({a = x}) { 'use strict'; function x() {}; return a; }
function f5({a = x}) { function x() {}; return a; }
assertEquals(1, f5({}));
})();
function f6({a = eval("x")}) { var x; return a; }
assertEquals(1, f6({}));
function f61({a = eval("x")}) { 'use strict'; var x; return a; }
(function() {
'use strict';
function f61({a = eval("x")}) { var x; return a; }
assertEquals(1, f61({}));
})();
function f62({a = eval("'use strict'; x")}) { var x; return a; }
assertEquals(1, f62({}));
function f7({a = function() { return x }}) { var x; return a(); }
......@@ -759,8 +765,11 @@
assertEquals(1, f8({}));
function f9({a = () => eval("x")}) { var x; return a(); }
assertEquals(1, f9({}));
function f91({a = () => eval("x")}) { 'use strict'; var x; return a(); }
(function TestInitializedWithEvalArrowStrict() {
'use strict';
function f91({a = () => eval("x")}) { var x; return a(); }
assertEquals(1, f91({}));
})();
function f92({a = () => { 'use strict'; return eval("x") }}) { var x; return a(); }
assertEquals(1, f92({}));
function f93({a = () => eval("'use strict'; x")}) { var x; return a(); }
......@@ -770,16 +779,22 @@
assertEquals(1, g1({}));
var g2 = ({a = x}) => { function x() {}; return a; };
assertEquals(1, g2({}));
var g3 = ({a = x}) => { 'use strict'; let x = 2; return a; };
(function() {
'use strict';
var g3 = ({a = x}) => { let x = 2; return a; };
assertEquals(1, g3({}));
var g4 = ({a = x}) => { 'use strict'; const x = 2; return a; };
var g4 = ({a = x}) => { const x = 2; return a; };
assertEquals(1, g4({}));
var g5 = ({a = x}) => { 'use strict'; function x() {}; return a; };
var g5 = ({a = x}) => { function x() {}; return a; };
assertEquals(1, g5({}));
})();
var g6 = ({a = eval("x")}) => { var x; return a; };
assertEquals(1, g6({}));
var g61 = ({a = eval("x")}) => { 'use strict'; var x; return a; };
(function() {
'use strict';
var g61 = ({a = eval("x")}) => { var x; return a; };
assertEquals(1, g61({}));
})();
var g62 = ({a = eval("'use strict'; x")}) => { var x; return a; };
assertEquals(1, g62({}));
var g7 = ({a = function() { return x }}) => { var x; return a(); };
......@@ -788,10 +803,13 @@
assertEquals(1, g8({}));
var g9 = ({a = () => eval("x")}) => { var x; return a(); };
assertEquals(1, g9({}));
var g91 = ({a = () => eval("x")}) => { 'use strict'; var x; return a(); };
(function() {
'use strict';
var g91 = ({a = () => eval("x")}) => { var x; return a(); };
assertEquals(1, g91({}));
var g92 = ({a = () => { 'use strict'; return eval("x") }}) => { var x; return a(); };
var g92 = ({a = () => { return eval("x") }}) => { var x; return a(); };
assertEquals(1, g92({}));
})();
var g93 = ({a = () => eval("'use strict'; x")}) => { var x; return a(); };
assertEquals(1, g93({}));
......@@ -799,12 +817,15 @@
assertSame(f11, f11({}));
var f12 = function f({x = f}) { function f() {}; return x; }
assertSame(f12, f12({}));
var f13 = function f({x = f}) { 'use strict'; let f; return x; }
(function() {
'use strict';
var f13 = function f({x = f}) { let f; return x; }
assertSame(f13, f13({}));
var f14 = function f({x = f}) { 'use strict'; const f = 0; return x; }
var f14 = function f({x = f}) { const f = 0; return x; }
assertSame(f14, f14({}));
var f15 = function f({x = f}) { 'use strict'; function f() {}; return x; }
var f15 = function f({x = f}) { function f() {}; return x; }
assertSame(f15, f15({}));
})();
var f16 = function f({f = 7, x = f}) { return x; }
assertSame(7, f16({}));
......@@ -827,9 +848,12 @@
function f2({a = eval("x")}, x) { return a }
assertThrows(() => f2({}, 4), ReferenceError);
assertEquals(4, f2({a: 4}, 5));
function f3({a = eval("x")}, x) { 'use strict'; return a }
(function() {
'use strict';
function f3({a = eval("x")}, x) { return a }
assertThrows(() => f3({}, 4), ReferenceError);
assertEquals(4, f3({a: 4}, 5));
})();
function f4({a = eval("'use strict'; x")}, x) { return a }
assertThrows(() => f4({}, 4), ReferenceError);
assertEquals(4, f4({a: 4}, 5));
......@@ -838,8 +862,11 @@
assertEquals(4, f5({a: () => 4}, 5));
function f6({a = () => eval("x")}, x) { return a() }
assertEquals(4, f6({a: () => 4}, 5));
function f7({a = () => eval("x")}, x) { 'use strict'; return a() }
(function() {
'use strict';
function f7({a = () => eval("x")}, x) { return a() }
assertEquals(4, f7({a: () => 4}, 5));
})();
function f8({a = () => eval("'use strict'; x")}, x) { return a() }
assertEquals(4, f8({a: () => 4}, 5));
......@@ -849,9 +876,12 @@
function f12({a = eval("b")}, {b}) { return a }
assertThrows(() => f12({}, {b: 4}), ReferenceError);
assertEquals(4, f12({a: 4}, {b: 5}));
function f13({a = eval("b")}, {b}) { 'use strict'; return a }
(function() {
'use strict';
function f13({a = eval("b")}, {b}) { return a }
assertThrows(() => f13({}, {b: 4}), ReferenceError);
assertEquals(4, f13({a: 4}, {b: 5}));
})();
function f14({a = eval("'use strict'; b")}, {b}) { return a }
assertThrows(() => f14({}, {b: 4}), ReferenceError);
assertEquals(4, f14({a: 4}, {b: 5}));
......@@ -860,8 +890,11 @@
assertEquals(4, f15({a: () => 4}, {b: 5}));
function f16({a = () => eval("b")}, {b}) { return a() }
assertEquals(4, f16({a: () => 4}, {b: 5}));
function f17({a = () => eval("b")}, {b}) { 'use strict'; return a() }
(function() {
'use strict';
function f17({a = () => eval("b")}, {b}) { return a() }
assertEquals(4, f17({a: () => 4}, {b: 5}));
})();
function f18({a = () => eval("'use strict'; b")}, {b}) { return a() }
assertEquals(4, f18({a: () => 4}, {b: 5}));
......@@ -885,8 +918,11 @@
assertEquals(4, f35({}, 4));
function f36({x = () => eval("a")}, ...a) { return x()[0] }
assertEquals(4, f36({}, 4));
function f37({x = () => eval("a")}, ...a) { 'use strict'; return x()[0] }
(function() {
'use strict';
function f37({x = () => eval("a")}, ...a) { return x()[0] }
assertEquals(4, f37({}, 4));
})();
function f38({x = () => { 'use strict'; return eval("a") }}, ...a) { return x()[0] }
assertEquals(4, f38({}, 4));
function f39({x = () => eval("'use strict'; a")}, ...a) { return x()[0] }
......@@ -969,3 +1005,19 @@
assertEquals(1, (function(x, {y} = {}, {z}, {v} = {}) {}).length);
assertEquals(1, (function({x}, {y} = {}, {z}, {v} = {}, ...a) {}).length);
})();
(function TestDirectiveThrows() {
"use strict";
assertThrows(function(){ eval("function({}){'use strict';}") }, SyntaxError);
assertThrows(function(){ eval("({}) => {'use strict';}") }, SyntaxError);
assertThrows(
function(){ eval("(class{foo({}) {'use strict';}});") }, SyntaxError);
assertThrows(
function(){ eval("function(a, {}){'use strict';}") }, SyntaxError);
assertThrows(function(){ eval("(a, {}) => {'use strict';}") }, SyntaxError);
assertThrows(
function(){ eval("(class{foo(a, {}) {'use strict';}});") }, SyntaxError);
})();
......@@ -16,8 +16,9 @@
return args.length; })(1,2,3,4,5));
})();
function strictTest(a, b, ...c) {
var strictTest = (function() {
"use strict";
return function strictTest(a, b, ...c) {
assertEquals(Array, c.constructor);
assertTrue(Array.isArray(c));
......@@ -27,7 +28,8 @@ function strictTest(a, b, ...c) {
for (var i = 2, j = 0; i < arguments.length; ++i) {
assertEquals(c[j++], arguments[i]);
}
}
};
})();
function sloppyTest(a, b, ...c) {
assertEquals(Array, c.constructor);
......@@ -144,14 +146,15 @@ var O = {
(function testNoAliasArgumentsStrict() {
function strictF(a, ...rest) {
((function() {
"use strict";
return (function strictF(a, ...rest) {
arguments[0] = 1;
assertEquals(3, a);
arguments[1] = 2;
assertArrayEquals([4, 5], rest);
}
strictF(3, 4, 5);
});
})())(3, 4, 5);
})();
......@@ -212,3 +215,21 @@ var O = {
assertEquals([1, 2, 3], c.child);
assertEquals([1, 2, 3], c.base);
})();
(function TestDirectiveThrows() {
"use strict";
assertThrows(
function(){ eval("function(...rest){'use strict';}") }, SyntaxError);
assertThrows(function(){ eval("(...rest) => {'use strict';}") }, SyntaxError);
assertThrows(
function(){ eval("(class{foo(...rest) {'use strict';}});") }, SyntaxError);
assertThrows(
function(){ eval("function(a, ...rest){'use strict';}") }, SyntaxError);
assertThrows(
function(){ eval("(a, ...rest) => {'use strict';}") }, SyntaxError);
assertThrows(
function(){ eval("(class{foo(a, ...rest) {'use strict';}});") },
SyntaxError);
})();
......@@ -4,17 +4,28 @@
// Flags: --harmony-spreadcalls --harmony-sloppy --harmony-rest-parameters
(function testCallSuperProperty() {
(function testCallSuperPropertyStrict() {
"use strict";
class BaseClass {
strict_method(...args) { "use strict"; return [this].concat(args); }
sloppy_method(...args) { return [this].concat(args); }
method(...args) { return [this].concat(args); }
}
class SubClass extends BaseClass {
strict_m(...args) { return super.strict_method(...args); }
sloppy_m(...args) { return super.sloppy_method(...args); }
method(...args) { return super.method(...args); }
}
var c = new SubClass();
assertEquals([c, 1, 2, 3, 4, 5], c.strict_m(1, 2, 3, 4, 5));
assertEquals([c, 1, 2, 3, 4, 5], c.sloppy_m(1, 2, 3, 4, 5));
assertEquals([c, 1, 2, 3, 4, 5], c.method(1, 2, 3, 4, 5));
})();
(function testCallSuperPropertySloppy() {
class BaseClass {
method(...args) { return [this].concat(args); }
}
class SubClass extends BaseClass {
method(...args) { return super.method(...args); }
}
var c = new SubClass();
assertEquals([c, 1, 2, 3, 4, 5], c.method(1, 2, 3, 4, 5));
})();
......@@ -6,7 +6,10 @@
// Flags: --harmony-arrow-functions --strong-mode --allow-natives-syntax
(function() {
function f({ x = function() { return []; } }) { "use strong"; return x(); }
var f = (function() {
"use strong";
return function f({ x = function() { return []; } }) { return x(); };
})();
var a = f({ x: undefined });
assertTrue(%IsStrong(a));
......@@ -19,7 +22,10 @@
assertFalse(%IsStrong(a));
function outerf() { return []; }
function f2({ x = outerf }) { "use strong"; return x(); }
var f2 = (function() {
"use strong";
return function f2({ x = outerf }) { return x(); };
})();
a = f2({ x: undefined });
assertFalse(%IsStrong(a));
})();
......@@ -21,7 +21,7 @@ function generateArguments(n, prefix) {
}
function generateParams(n) {
function generateParams(n, directive_in_body) {
let a = [];
for (let i = 0; i < n; i++) {
a[i] = `p${i}`;
......@@ -29,13 +29,17 @@ function generateParams(n) {
return a.join(', ');
}
function generateParamsWithRest(n) {
function generateParamsWithRest(n, directive_in_body) {
let a = [];
let i = 0;
for (; i < n; i++) {
a[i] = `p${i}`;
}
a.push(`...p${i}`)
if (!directive_in_body) {
// If language mode directive occurs in body, rest parameters will trigger
// an early error regardless of language mode.
a.push(`...p${i}`);
}
return a.join(', ');
}
......@@ -76,6 +80,7 @@ function generateSpread(n) {
for (let call of calls) {
let code = `'use strict'; ${def}; ${call};`;
if (argumentCount < parameterCount) {
print(code);
assertThrows(code, TypeError);
} else {
assertDoesNotThrow(code);
......@@ -106,13 +111,13 @@ function generateSpread(n) {
for (let parameterCount = 0; parameterCount < 3; parameterCount++) {
let defs = [
`let o = new class {
m(${genParams(parameterCount)}) { 'use strong'; }
m(${genParams(parameterCount, true)}) { 'use strong'; }
}`,
`let o = new class {
*m(${genParams(parameterCount)}) { 'use strong'; }
*m(${genParams(parameterCount, true)}) { 'use strong'; }
}`,
`let o = { m(${genParams(parameterCount)}) { 'use strong'; } }`,
`let o = { *m(${genParams(parameterCount)}) { 'use strong'; } }`,
`let o = { m(${genParams(parameterCount, true)}) { 'use strong'; } }`,
`let o = { *m(${genParams(parameterCount, true)}) { 'use strong'; } }`,
`'use strong';
let o = new class { m(${genParams(parameterCount)}) {} }`,
`'use strong';
......@@ -173,7 +178,7 @@ function generateSpread(n) {
class C { constructor(${genParams(parameterCount)}) {} }`,
`'use strict';
class C {
constructor(${genParams(parameterCount)}) { 'use strong'; }
constructor(${genParams(parameterCount, true)}) { 'use strong'; }
}`,
];
for (let def of defs) {
......@@ -214,7 +219,7 @@ function generateSpread(n) {
}`,
`'use strict';
class B {
constructor(${genParams(parameterCount)}) { 'use strong'; }
constructor(${genParams(parameterCount, true)}) { 'use strong'; }
}
class C extends B {
constructor() {
......@@ -250,7 +255,7 @@ function generateSpread(n) {
class C extends B {}`,
`'use strict';
class B {
constructor(${genParams(parameterCount)}) { 'use strong'; }
constructor(${genParams(parameterCount, true)}) { 'use strong'; }
}
class C extends B {}`,
];
......
......@@ -112,14 +112,14 @@
assertWeakArray({a: [], b: {}}.a);
})();
(function StrongArrayLiterals(...args) {
(function StrongArrayLiterals() {
'use strong';
function assertStrongArray(x) {
assertTrue(%IsStrong(x));
assertSame(Array.prototype, Object.getPrototypeOf(x));
}
let [...r] = [];
assertStrongArray(args);
assertStrongArray((function(...a) { return a; })());
assertStrongArray(r);
assertStrongArray([]);
assertStrongArray([1, 2, 3]);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment