Commit dfce900d authored by caitpotter88's avatar caitpotter88 Committed by Commit bot

[es6] enable destructuring rest parameters

Originally, only BindingIdentifiers were a legal operand for the `...` ellipsis
in a function rest parameter. This has since changed, allowing the rest array
to be destructured.

The grammar is now the following:

```
FunctionRestParameter[Yield]:
    BindingRestElement[?Yield]

BindingRestElement[Yield]:
    ... BindingIdentifier[?Yield]
    ... BindingPattern[?Yield]
```

*Spec change: https://github.com/tc39/ecma262/commit/d322357e6be95bc4bd3e03f5944a736aac55fa50
*TC39 Discussion: https://github.com/tc39/tc39-notes/blob/master/es7/2015-07/july-28.md#66-bindingrestelement-should-allow-a-bindingpattern-ala-assignmentrestelement

BUG=v8:4627, v8:2159
LOG=N
R=littledan@chromium.org, adamk@chromium.org, wingo@igalia.com, rossberg@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#33192}
parent 9de63d38
......@@ -1336,18 +1336,8 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
MessageTemplate::kUnexpectedToken,
Token::String(Token::ELLIPSIS));
classifier->RecordNonSimpleParameter();
Scanner::Location expr_loc = scanner()->peek_location();
Token::Value tok = peek();
ExpressionT expr =
this->ParseAssignmentExpression(true, classifier, CHECK_OK);
// Patterns are not allowed as rest parameters. There is no way we can
// succeed so go ahead and use the convenient ReportUnexpectedToken
// interface.
if (!Traits::IsIdentifier(expr)) {
ReportUnexpectedTokenAt(expr_loc, tok);
*ok = false;
return this->EmptyExpression();
}
if (peek() == Token::COMMA) {
ReportMessageAt(scanner()->peek_location(),
MessageTemplate::kParamAfterRest);
......@@ -2869,7 +2859,7 @@ void ParserBase<Traits>::ParseFormalParameter(
if (!*ok) return;
if (!Traits::IsIdentifier(pattern)) {
if (is_rest || !allow_harmony_destructuring_bind()) {
if (!allow_harmony_destructuring_bind()) {
ReportUnexpectedToken(next);
*ok = false;
return;
......
......@@ -4478,7 +4478,7 @@ Block* Parser::BuildParameterInitializationBlock(
factory()->NewBlock(NULL, 1, true, RelocInfo::kNoPosition);
for (int i = 0; i < parameters.params.length(); ++i) {
auto parameter = parameters.params[i];
if (parameter.is_rest) break;
if (parameter.is_rest && parameter.pattern->IsVariableProxy()) break;
DeclarationDescriptor descriptor;
descriptor.declaration_kind = DeclarationDescriptor::PARAMETER;
descriptor.parser = this;
......
......@@ -5295,21 +5295,27 @@ TEST(ParseRestParameters) {
"/regexp/, 'str', function(){});"},
{NULL, NULL}};
const char* data[] = {
"...args",
"a, ...args",
"... args",
"a, ... args",
"...\targs",
"a, ...\targs",
"...\r\nargs",
"a, ...\r\nargs",
"...\rargs",
"a, ...\rargs",
"...\t\n\t\t\n args",
"a, ... \n \n args",
NULL};
RunParserSyncTest(context_data, data, kSuccess);
const char* data[] = {"...args",
"a, ...args",
"... args",
"a, ... args",
"...\targs",
"a, ...\targs",
"...\r\nargs",
"a, ...\r\nargs",
"...\rargs",
"a, ...\rargs",
"...\t\n\t\t\n args",
"a, ... \n \n args",
"...{ length, 0: a, 1: b}",
"...{}",
"...[a, b]",
"...[]",
"...[...[a, b, ...c]]",
NULL};
static const ParserFlag always_flags[] = {kAllowHarmonyDestructuring};
RunParserSyncTest(context_data, data, kSuccess, nullptr, 0, always_flags,
arraysize(always_flags));
}
......@@ -7202,30 +7208,6 @@ TEST(DestructuringDisallowPatternsInSingleParamArrows) {
}
TEST(DestructuringDisallowPatternsInRestParams) {
i::FLAG_harmony_destructuring_bind = true;
static const ParserFlag always_flags[] = {kAllowHarmonyDestructuring};
const char* context_data[][2] = {{"'use strict';", ""},
{"function outer() { 'use strict';", "}"},
{"", ""},
{"function outer() { ", "}"},
{nullptr, nullptr}};
// clang-format off
const char* error_data[] = {
"function(...{}) {}",
"function(...{x}) {}",
"function(...[x]) {}",
"(...{}) => {}",
"(...{x}) => {}",
"(...[x]) => {}",
nullptr};
// clang-format on
RunParserSyncTest(context_data, error_data, kError, NULL, 0, always_flags,
arraysize(always_flags));
}
TEST(DefaultParametersYieldInInitializers) {
// clang-format off
const char* sloppy_function_context_data[][2] = {
......
......@@ -217,3 +217,26 @@ var O = {
function(){ eval("(class{foo(a, ...rest) {'use strict';}});") },
SyntaxError);
})();
(function TestRestArrayPattern() {
function f(...[a, b, c]) { return a + b + c; }
assertEquals(6, f(1, 2, 3));
assertEquals("123", f(1, "2", 3));
assertEquals(NaN, f(1));
var f2 = (...[a, b, c]) => a + b + c;
assertEquals(6, f2(1, 2, 3));
assertEquals("123", f2(1, "2", 3));
assertEquals(NaN, f2(1));
})();
(function TestRestObjectPattern() {
function f(...{length, 0: firstName, 1: lastName}) {
return `Hello ${lastName}, ${firstName}! Called with ${length} args!`;
}
assertEquals("Hello Ross, Bob! Called with 4 args!", f("Bob", "Ross", 0, 0));
var f2 = (...{length, 0: firstName, 1: lastName}) =>
`Hello ${lastName}, ${firstName}! Called with ${length} args!`;
assertEquals("Hello Ross, Bob! Called with 4 args!", f2("Bob", "Ross", 0, 0));
})();
......@@ -389,10 +389,6 @@
'intl402/String/prototype/toLocaleUpperCase/special_casing_Lithuanian': [FAIL],
'intl402/String/prototype/toLocaleUpperCase/special_casing_Turkish': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=4627
'language/rest-parameters/object-pattern': [FAIL],
'language/rest-parameters/array-pattern': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=4628
'language/eval-code/non-definable-function-with-variable': [FAIL],
'language/eval-code/non-definable-function-with-function': [FAIL],
......
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