[parser] Fix crash when lazy arrow func params contain destructuring assignments.

As far as I can see, we have had this bug as long as destructuring assignments
have been there (i.e., this is not regression).

The problem was that Parser::DoParseFunction parsed the arrow function parameters
but didn't rewrite the destructuring assignments in them.

BUG=chromium:704811

Change-Id: I0b1424e7d5103eda6efd51b403fe81a4ee235e01
Reviewed-on: https://chromium-review.googlesource.com/459618
Commit-Queue: Marja Hölttä <marja@chromium.org>
Reviewed-by: Adam Klein <adamk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#44177}
This commit is contained in:
Marja Hölttä 2017-03-28 07:53:26 +02:00 committed by Commit Bot
parent 80752a29b6
commit bc39a5148a
2 changed files with 92 additions and 0 deletions

View File

@ -937,6 +937,10 @@ FunctionLiteral* Parser::DoParseFunction(ParseInfo* info,
// must produce a FunctionLiteral.
DCHECK(expression->IsFunctionLiteral());
result = expression->AsFunctionLiteral();
// Rewrite destructuring assignments in the parameters. (The ones
// inside the function body are rewritten by
// ParseArrowFunctionLiteral.)
RewriteDestructuringAssignments();
} else {
ok = false;
}

View File

@ -0,0 +1,88 @@
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// The bug was that destructuring assignments which occur inside a lazy arrow
// function parameter list were not rewritten.
// Repro from the bug (slightly modified so that it doesn't produce a run-time
// exception).
(({x = {} = {}}) => {})({});
// ... and without the parens.
let a0 = ({x = {} = {}}) => {};
a0({});
// Testing that the destructuring assignments also work properly. The semantics
// are: The value of the destructuring assignment is an object {myprop: 2115}
// and 2115 also gets assigned to global_side_assignment. So the default value
// for x is {myprop: 2115}. This is the value which x will have if the function
// is called with an object which doesn't have property x.
let called = false;
let global_side_assignment = undefined;
(({x = {myprop: global_side_assignment} = {myprop: 2115}}) => {
assertTrue('myprop' in x);
assertEquals(2115, x.myprop);
called = true;
})({});
assertTrue(called);
assertEquals(2115, global_side_assignment);
// If the parameter is an object which has property x, the default value is not
// used.
called = false;
global_side_assignment = undefined;
(({x = {myprop: global_side_assignment} = {myprop: 2115}}) => {
assertEquals(3000, x);
called = true;
})({x: 3000});
assertTrue(called);
// Global side assignment doesn't happen, since the default value was not used.
assertEquals(undefined, global_side_assignment);
// Different kinds of lazy arrow functions (it's actually a bit weird that the
// above functions are lazy, since they are parenthesized).
called = false;
global_side_assignment = undefined;
let a1 = ({x = {myprop: global_side_assignment} = {myprop: 2115}}) => {
assertTrue('myprop' in x);
assertEquals(2115, x.myprop);
called = true;
}
a1({});
assertTrue(called);
assertEquals(2115, global_side_assignment);
called = false;
global_side_assignment = undefined;
let a2 = ({x = {myprop: global_side_assignment} = {myprop: 2115}}) => {
assertEquals(3000, x);
called = true;
}
a2({x: 3000});
assertTrue(called);
assertEquals(undefined, global_side_assignment);
// We never had a problem with non-arrow functions, but testing them too for
// completeness.
called = false;
global_side_assignment = undefined;
function f1({x = {myprop: global_side_assignment} = {myprop: 2115}}) {
assertTrue('myprop' in x);
assertEquals(2115, x.myprop);
assertEquals(2115, global_side_assignment);
called = true;
}
f1({});
assertTrue(called);
assertEquals(2115, global_side_assignment);
called = false;
global_side_assignment = undefined;
function f2({x = {myprop: global_side_assignment} = {myprop: 2115}}) {
assertEquals(3000, x);
called = true;
}
f2({x: 3000});
assertTrue(called);
assertEquals(undefined, global_side_assignment);