Commit 0b3b7267 authored by rossberg's avatar rossberg Committed by Commit bot

[es6] Correct length for functions with default parameters

R=adamk@chromium.org
BUG=v8:2160
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#30361}
parent 09b54808
...@@ -1338,8 +1338,9 @@ void ParserTraits::DeclareFormalParameter( ...@@ -1338,8 +1338,9 @@ void ParserTraits::DeclareFormalParameter(
auto name = is_simple || parameter.is_rest auto name = is_simple || parameter.is_rest
? parameter.name : parser_->ast_value_factory()->empty_string(); ? parameter.name : parser_->ast_value_factory()->empty_string();
auto mode = is_simple || parameter.is_rest ? VAR : TEMPORARY; auto mode = is_simple || parameter.is_rest ? VAR : TEMPORARY;
Variable* var = bool is_optional = parameter.initializer != nullptr;
scope->DeclareParameter(name, mode, parameter.is_rest, &is_duplicate); Variable* var = scope->DeclareParameter(
name, mode, is_optional, parameter.is_rest, &is_duplicate);
if (is_duplicate) { if (is_duplicate) {
classifier->RecordDuplicateFormalParameterError( classifier->RecordDuplicateFormalParameterError(
parser_->scanner()->location()); parser_->scanner()->location());
......
...@@ -180,6 +180,7 @@ void Scope::SetDefaults(ScopeType scope_type, Scope* outer_scope, ...@@ -180,6 +180,7 @@ void Scope::SetDefaults(ScopeType scope_type, Scope* outer_scope,
num_global_slots_ = 0; num_global_slots_ = 0;
num_modules_ = 0; num_modules_ = 0;
module_var_ = NULL; module_var_ = NULL;
arity_ = 0;
has_simple_parameters_ = true; has_simple_parameters_ = true;
rest_parameter_ = NULL; rest_parameter_ = NULL;
rest_index_ = -1; rest_index_ = -1;
...@@ -465,10 +466,12 @@ Variable* Scope::Lookup(const AstRawString* name) { ...@@ -465,10 +466,12 @@ Variable* Scope::Lookup(const AstRawString* name) {
} }
Variable* Scope::DeclareParameter(const AstRawString* name, VariableMode mode, Variable* Scope::DeclareParameter(
bool is_rest, bool* is_duplicate) { const AstRawString* name, VariableMode mode,
bool is_optional, bool is_rest, bool* is_duplicate) {
DCHECK(!already_resolved()); DCHECK(!already_resolved());
DCHECK(is_function_scope()); DCHECK(is_function_scope());
DCHECK(!is_optional || !is_rest);
Variable* var; Variable* var;
if (mode == TEMPORARY) { if (mode == TEMPORARY) {
var = NewTemporary(name); var = NewTemporary(name);
...@@ -479,6 +482,9 @@ Variable* Scope::DeclareParameter(const AstRawString* name, VariableMode mode, ...@@ -479,6 +482,9 @@ Variable* Scope::DeclareParameter(const AstRawString* name, VariableMode mode,
// TODO(wingo): Avoid O(n^2) check. // TODO(wingo): Avoid O(n^2) check.
*is_duplicate = IsDeclaredParameter(name); *is_duplicate = IsDeclaredParameter(name);
} }
if (!is_optional && !is_rest && arity_ == params_.length()) {
++arity_;
}
if (is_rest) { if (is_rest) {
DCHECK_NULL(rest_parameter_); DCHECK_NULL(rest_parameter_);
rest_parameter_ = var; rest_parameter_ = var;
......
...@@ -128,8 +128,9 @@ class Scope: public ZoneObject { ...@@ -128,8 +128,9 @@ class Scope: public ZoneObject {
// Declare a parameter in this scope. When there are duplicated // Declare a parameter in this scope. When there are duplicated
// parameters the rightmost one 'wins'. However, the implementation // parameters the rightmost one 'wins'. However, the implementation
// expects all parameters to be declared and from left to right. // expects all parameters to be declared and from left to right.
Variable* DeclareParameter(const AstRawString* name, VariableMode mode, Variable* DeclareParameter(
bool is_rest, bool* is_duplicate); const AstRawString* name, VariableMode mode,
bool is_optional, bool is_rest, bool* is_duplicate);
// Declare a local variable in this scope. If the variable has been // Declare a local variable in this scope. If the variable has been
// declared before, the previously declared variable is returned. // declared before, the previously declared variable is returned.
...@@ -369,16 +370,8 @@ class Scope: public ZoneObject { ...@@ -369,16 +370,8 @@ class Scope: public ZoneObject {
return params_[index]; return params_[index];
} }
// Returns the default function arity --- does not include rest parameters. // Returns the default function arity excluding default or rest parameters.
int default_function_length() const { int default_function_length() const { return arity_; }
int count = params_.length();
if (rest_index_ >= 0) {
DCHECK(count > 0);
DCHECK(is_function_scope());
--count;
}
return count;
}
int num_parameters() const { return params_.length(); } int num_parameters() const { return params_.length(); }
...@@ -636,6 +629,7 @@ class Scope: public ZoneObject { ...@@ -636,6 +629,7 @@ class Scope: public ZoneObject {
Variable* module_var_; Variable* module_var_;
// Info about the parameter list of a function. // Info about the parameter list of a function.
int arity_;
bool has_simple_parameters_; bool has_simple_parameters_;
Variable* rest_parameter_; Variable* rest_parameter_;
int rest_index_; int rest_index_;
......
...@@ -362,15 +362,14 @@ ...@@ -362,15 +362,14 @@
(function TestFunctionLength() { (function TestFunctionLength() {
// TODO(rossberg): Fix arity. assertEquals(0, (function(x = 1) {}).length);
// assertEquals(0, (function(x = 1) {}).length); assertEquals(0, (function(x = 1, ...a) {}).length);
// assertEquals(0, (function(x = 1, ...a) {}).length); assertEquals(1, (function(x, y = 1) {}).length);
// assertEquals(1, (function(x, y = 1) {}).length); assertEquals(1, (function(x, y = 1, ...a) {}).length);
// assertEquals(1, (function(x, y = 1, ...a) {}).length); assertEquals(2, (function(x, y, z = 1) {}).length);
// assertEquals(2, (function(x, y, z = 1) {}).length); assertEquals(2, (function(x, y, z = 1, ...a) {}).length);
// assertEquals(2, (function(x, y, z = 1, ...a) {}).length); assertEquals(1, (function(x, y = 1, z) {}).length);
// assertEquals(1, (function(x, y = 1, z) {}).length); assertEquals(1, (function(x, y = 1, z, ...a) {}).length);
// assertEquals(1, (function(x, y = 1, z, ...a) {}).length); assertEquals(1, (function(x, y = 1, z, v = 2) {}).length);
// assertEquals(1, (function(x, y = 1, z, v = 2) {}).length); assertEquals(1, (function(x, y = 1, z, v = 2, ...a) {}).length);
// assertEquals(1, (function(x, y = 1, z, v = 2, ...a) {}).length);
})(); })();
...@@ -953,3 +953,19 @@ ...@@ -953,3 +953,19 @@
assertThrows("'use strict'; let x = {}; for (let [x, y] in {x});", ReferenceError); assertThrows("'use strict'; let x = {}; for (let [x, y] in {x});", ReferenceError);
assertThrows("'use strict'; let x = {}; for (let [y, x] in {x});", ReferenceError); assertThrows("'use strict'; let x = {}; for (let [y, x] in {x});", ReferenceError);
}()); }());
(function TestFunctionLength() {
assertEquals(1, (function({}) {}).length);
assertEquals(1, (function([]) {}).length);
assertEquals(1, (function({x}) {}).length);
assertEquals(1, (function({}, ...a) {}).length);
assertEquals(1, (function({x}, {y} = {}) {}).length);
assertEquals(1, (function({x}, {y} = {}, ...a) {}).length);
assertEquals(2, (function(x, {y}, {z} = {}) {}).length);
assertEquals(2, (function({x}, {}, {z} = {}, ...a) {}).length);
assertEquals(1, (function(x, {y} = {}, {z}) {}).length);
assertEquals(1, (function({x}, {y} = {}, {z}, ...a) {}).length);
assertEquals(1, (function(x, {y} = {}, {z}, {v} = {}) {}).length);
assertEquals(1, (function({x}, {y} = {}, {z}, {v} = {}, ...a) {}).length);
})();
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